JUC
wait/sleep区别
-
来源不同
wait是Object实例方法
sleep是Thread的静态方法
-
锁的释放
wait会释放锁,
sleep不会释放锁
-
使用地方
wait在同步代码或者同步代码块中使用,不需要捕获异常
sleep可以在任何地方使用,需要捕获异常
-
唤醒方式
wait需要被notify或者notifyAll方法
sleep需要等待时间结束或者使用Interrupt()方法
ReentrantReadWriteLock
ReentrantReadWriteLock是Java中一个可重入的读写锁(ReentrantReadWriteLock)。它允许多个线程同时读取一个共享资源,但只允许一个线程写入该共享资源。
ReentrantReadWriteLock由两个锁组成:读锁和写锁。在任意时刻,可以同时有多个线程持有读锁,但只允许一个线程持有写锁。当一个线程持有写锁时,其他线程无法获取读锁或写锁。
与普通的排它锁相比,使用ReentrantReadWriteLock可以提高并发性能,在读多写少的场景下特别有效。此外,与synchronized关键字不同,ReentrantReadWriteLock提供了更细粒度的控制,允许对读写操作进行分离管理,从而更加灵活地控制共享资源的访问方式。
需要注意的是,ReentrantReadWriteLock虽然可以提高并发性能,但也存在一些潜在问题,如写饥饿、读锁饥饿和锁降级等问题。因此,在使用ReentrantReadWriteLock时,需要根据具体情况进行评估和选择。
ReentrantLock和ReentrantReadWriteLock区别
ReentrantLock和ReentrantReadWriteLock都是Java中可重入的锁,它们有一些区别:
- 锁类型不同:ReentrantLock是排它锁,每次只能被一个线程获取;而ReentrantReadWriteLock是读写锁,支持多个读线程同时访问共享资源,但只允许一个写线程访问共享资源。
- 加锁方式不同:在使用ReentrantLock时,需要显式地去加锁和释放锁,即通过lock()和unlock()方法来控制。而在使用ReentrantReadWriteLock时,可以通过readLock()方法获取读锁,writeLock()方法获取写锁,然后分别调用lock()和unlock()方法进行加锁和释放锁。
- 锁粒度不同:由于ReentrantReadWriteLock允许多个读操作同时进行,因此其锁粒度更细,也更适合读多写少的场景。而ReentrantLock是排它锁,每次只允许一个线程访问共享资源,会导致其他线程阻塞等待,因此对于写多的场景表现更好。
- 性能差异:ReentrantLock是轻量级锁,没有读写锁的附加开销,因此在单线程或竞争不激烈的情况下性能较好。而ReentrantReadWriteLock是读写锁,具有更细粒度的控制,可以允许多个读操作同时进行 ,因此在读多写少的情况下性能更好。
锁降级
锁降级是指将一个使用了排它锁(如ReentrantLock)的代码块,在该锁保护下完成了一些任务后,再切换为使用共享锁(如读写锁中的读锁),以提高并发性能和减少锁竞争的策略。
在锁降级的过程中,首先获取排它锁,执行一些需要保护的操作,然后释放排它锁,获取共享锁,继续执行后面的共享操作。这样可以让其他线程也可以同时持有共享锁来访问和修改数据,从而提高并发性能。同时,由于降低了锁的粒度,也减少了锁的竞争,进一步提高了程序的效率。
需要注意的是,在进行锁降级时,必须确保拥有读锁的线程对数据的修改不会影响到其他线程的读取结果,否则可能会导致数据的不一致性。因此,在进行锁降级时,需要仔细评估程序的逻辑,确保线程安全性。