最近出现一个需求,大体要做的就是控制多线程同时操作一个文件。当时第一个反应是不要用synchronized,太low了,然后我就使用了读写锁ReentrantReadWriteLock,然后写完静下来和业务结合在一起分析一下,结果尴尬了。因为文件名可能是别的线程刚刚生成的带上了时间戳,线程A写orders_201904171130.xls文件,线程B写orders_201904171131.xls文件,这个时候实际上时不能阻塞的。Lock没办法像synchronized关键字一样,给定一把锁,锁住特定的对象。锁对象不同,则不阻塞
然后试着使用synchronized代码块,使用filename作为锁对象,初一看好像可以,但是经不住测试哇,测试的时候即使同一个文件名,还是不能阻塞,因为filename是属于拼接起来的,且还是局部变量,所以这个filename的string虽然在常量池中值是一样的,但是在堆里的对象地址是不一样的,所以synchronized认为不是同一个对象锁,所以同一个文件名并没有阻塞
然后想起来使用RandomAccessFile和FileLock实现,但是我这种情况下是往远程服务器共享目录读写,File类是用不了的。所以他也用不了。
然后这个时候回到了synchronized,既然每次String的堆地址变化了,那我能不能让后面出现同样值的时候,返回同一个引用呢。然后发现String的intent()方法可以做到。它的返回值:一个字符串,内容与此字符串相同,但一定取自具有唯一字符串的池。
public static void main(String[] args) { String str1 = "12345"; String temp1 = "123", temp2 = "45"; String str2 = new String("12345"); String str3 = temp1 + temp2; System.out.println("str1 = " + System.identityHashCode(str1)); System.out.println("str2 = " + System.identityHashCode(str2)); System.out.println("str3 = " + System.identityHashCode(str3)); System.out.println("str2.intern = " + System.identityHashCode(str2.intern())); System.out.println("str3.intern = " + System.identityHashCode(str3.intern())); }
运行结果
附上RandomAccessFile和FileLock实现处理多人同时读写文件的处理连接