java多进程共享变量_Java 多进程文件锁 FileLock 相关实战解析

问:说说你对 FileLock 进程锁的认识?最好能举例说明你知道的各种场景?

答:FileLock 是进程文件锁,用于进程间并发,控制不同程序(JVM)对同一文件的并发访问,是 JDK 1.4 提供的一个类,可以通过对一个可写文件加锁,保证同时只有一个进程可以拿到文件锁,这个进程从而可以对文件进行操作,而其它拿不到锁的进程要么被挂起等待,要么可以去做一些其它事情,这种机制保证了进程间文件的并发安全操作。

而 FileLock 的使用核心离不开对独占锁和共享锁的理解。独占锁也叫排它锁,如果一个任务获得一个文件的独占锁,那么其它任务就不能再获得同一文件的独占锁或共享锁,直到独占锁被释放。共享锁指的是如果一个任务获得一个文件的共享锁,那么其它任务可以获得同一文件的共享锁或同一文件部分内容的共享锁,但不能获得独占锁,共享锁情况下是不支持写操作的。

此外 FileLock 文件锁的效果是与操作系统相关的,是由操作系统底层来实现(如在 Win 的进程间不能同时读写一个文件,而在 Linux 的不同进程可以同时读写一个文件)。

所以基于此可以通过控制变量法总结出如下几种伪代码解析。

//进程1代码片段

RandomAccessFile randomAccessFile = new RandomAccessFile("test.txt", "rw");

FileChannel channel = randomAccessFile.getChannel();

FileLock lock = channel.lock();

for (int i = 0; i < 10; i++) {

randomAccessFile.writeChars("1");

Thread.sleep(1000);

}

lock.release();

randomAccessFile.close();

channel.close();

进程2代码片段

RandomAccessFile randomAccessFile = new RandomAccessFile("test.txt", "rw");

FileChannel channel = randomAccessFile.getChannel();

FileLock lock = channel.lock();

randomAccessFile.length();

lock.release();

randomAccessFile.close();

channel.close();

//如上程序先运行进程1,然后同时启动进程2。

//会发现进程2会等到进程1执行完lock.release()后才开始执行channel.lock()之后的代码,

//这期间进程2会一直阻塞挂起等待进程1释放锁。

//此时进程1,2使用的都是独占锁,这是进程并发写操作最常用的一种手段。

//进程1代码片段

RandomAccessFile randomAccessFile = new RandomAccessFile("test.txt", "rw");

FileChannel channel = randomAccessFile.getChannel();

FileLock lock = channel.lock();

for (int i = 0; i < 10; i++) {

randomAccessFile.writeChars("1");

Thread.sleep(1000);

}

lock.release();

randomAccessFile.close();

channel.close();

进程2代码片段

RandomAccessFile randomAccessFile = new RandomAccessFile("test.txt", "rw");

FileChannel channel = randomAccessFile.getChannel();

FileLock lock = channel.lock(0, Integer.MAX_VALUE, true);

randomAccessFile.length();

lock.release();

randomAccessFile.close();

channel.close();

//如上程序先运行进程1,然后同时启动进程2。

//会发现进程2会等到进程1执行完lock.release()后才开始执行channel.lock(0, Integer.MAX_VALUE, true)之后的代码,

//这期间进程2会一直阻塞挂起等待进程1释放锁。

//此时进程1使用的是独占锁,进程2使用的是共享锁,所以如上语言总结。

//即如果一个任务获得一个文件的独占锁,那么其它任务就不能再获得同一文件的独占锁或共享锁,直到独占锁被释放。

//此处便是这种情况。

//进程1代码片段

RandomAccessFile randomAccessFile = new RandomAccessFile("test.txt", "rw");

FileChannel channel = randomAccessFile.getChannel();

FileLock lock = channel.lock(0, Integer.MAX_VALUE, true);

for (int i = 0; i < 10; i++) {

randomAccessFile.writeChars("1");

Thread.sleep(1000);

}

lock.release();

randomAccessFile.close();

channel.close();

进程2代码片段

RandomAccessFile randomAccessFile = new RandomAccessFile("test.txt", "rw");

FileChannel channel = randomAccessFile.getChannel();

FileLock lock = channel.lock(0, Integer.MAX_VALUE, true);

randomAccessFile.length();

lock.release();

randomAccessFile.close();

channel.close();

//如上程序先运行进程1,然后同时启动进程2。

//会发现进程1会抛出IOException: 另一个程序已锁定文件的一部分,进程无法访问。at java.io.RandomAccessFile.writeBytes(Native Method) 异常。

//而进程2可以正常执行。

//此时进程1、2都使用的是共享锁,如上语言总结。

//共享锁是不允许写操作的,只允许读操作,所以进程1抛出写异常(Windows上)。

//进程1代码片段

RandomAccessFile randomAccessFile = new RandomAccessFile("test.txt", "rw");

FileChannel channel = randomAccessFile.getChannel();

FileLock lock = channel.lock(0, Integer.MAX_VALUE, true);

for (int i = 0; i < 10; i++) {

randomAccessFile.readLine();

Thread.sleep(1000);

}

lock.release();

randomAccessFile.close();

channel.close();

进程2代码片段

RandomAccessFile randomAccessFile = new RandomAccessFile("test.txt", "rw");

FileChannel channel = randomAccessFile.getChannel();

FileLock lock = channel.lock(0, Integer.MAX_VALUE, true);

randomAccessFile.length();

lock.release();

randomAccessFile.close();

channel.close();

//如上程序先运行进程1,然后同时启动进程2。

//会发现进程1、2都能无阻塞的执行。

//此时进程1、2都使用的是共享锁,如上语言总结。

//共享锁是不允许写操作的,只允许读操作,所以他们都能正常并发读操作。

所以综上案例可以再次总结如下:

当使用独占锁时,除了该进程,其他的进程都不能访问被锁定的文件,其他进程会阻塞在 lock() 代码处。

当使用独占锁时,该进程可以对文件进行写操作,因为此时其他试图获取锁的进程会被阻塞,此时执行写操作是并发安全的。

当使用共享锁时,所有其他进程都可以获取锁,并且可以并行的进行读操作。

当使用共享锁时,调用 write 方法修改文件会抛出异常,因为所有的进程都可以获取读文件锁,执行写操作是并发不安全的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Python多线程编程中,Lock)和可重入(RLock)都是常用的同步机制,用于保护共享资源,防止多个线程同时访问导致数据错误。 Lock是一种最基本的,它将资源住,直到被释放。当一个线程获得时,其他线程必须等待该线程释放后才能获得。这种是不可重入的,即同一个线程不能重复获得同一把。 RLock是可重入,它允许一个线程多次获得同一把。当一个线程获得时,它可以再次获得这个而不会被阻塞。只有该线程释放的次数与获得的次数相等时,其他线程才能获得该。可重入在需要多次获得同一把的场景中很有用。 下面是使用Lock和RLock的示例代码: ```python import threading # 创建一个Lock对象 lock = threading.Lock() # 创建一个RLock对象 rlock = threading.RLock() # 使用Lock保护共享资源 class Counter(object): def __init__(self): self.value = 0 def increment(self): lock.acquire() try: self.value += 1 finally: lock.release() # 使用RLock保护共享资源 class ReentrantCounter(object): def __init__(self): self.value = 0 def increment(self): rlock.acquire() try: self.value += 1 # 再次获得 rlock.acquire() try: self.value += 1 finally: rlock.release() finally: rlock.release() ``` 在上面的代码中,Counter类使用Lock保护value属性,而ReentrantCounter类使用RLock保护value属性。在increment方法中,Counter使用lock.acquire()和lock.release()获取和释放,在同一时间只允许一个线程访问value属性。而ReentrantCounter使用rlock.acquire()和rlock.release()获取和释放,并且在方法内部重复获得,这是RLock的特性。 需要注意的是,使用时要避免死的情况发生,即多个线程相互等待对方释放的情况。因此,在编写代码时要考虑好的获取和释放顺序,以避免死的发生。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值