ReentrantReadWriteLock
读锁和写锁互斥,相互阻塞 写锁和写锁互斥,相互阻塞 读锁和读锁不互斥,不阻塞
持有读锁的情况下去获取写锁,会导致获取写锁永久等待(重入时升级不支持) 即持有写锁的情况下去获取读锁,不阻塞(重入时降级支持)
示例
12345678910111213141516171819202122232425262728293031323334353637383940414243444546 | @Slf4j(topic = "c.TestReadWriteLock")public class TestReadWriteLock { public static void main(String[] args) throws InterruptedException { DataContainer dataContainer = new DataContainer(); new Thread(() -> { dataContainer.read(); }, "t1").start(); new Thread(() -> { dataContainer.read(); }, "t2").start(); }}@Slf4j(topic = "c.DataContainer")class DataContainer { private Object data; private ReentrantReadWriteLock rw = new ReentrantReadWriteLock(); private ReentrantReadWriteLock.ReadLock r = rw.readLock(); private ReentrantReadWriteLock.WriteLock w = rw.writeLock(); public Object read() { log.debug("获取读锁..."); r.lock(); try { log.debug("读取"); sleep(1); return data; } finally { log.debug("释放读锁..."); r.unlock(); } } public void write() { log.debug("获取写锁..."); w.lock(); try { log.debug("写入"); sleep(1); } finally { log.debug("释放写锁..."); w.unlock(); } }} |
---|
锁对象
123 | private ReentrantReadWriteLock rw = new ReentrantReadWriteLock();private ReentrantReadWriteLock.ReadLock r = rw.readLock();private ReentrantReadWriteLock.WriteLock w = rw.writeLock(); |
---|
加锁解锁
12 | r.lock();r.unlock |
---|
StampedLock
带时间戳的读写锁,该类自 JDK 8 加入,进一步优化读性能,可支持乐观读,如果写操作不多,读操作多,可用该锁。
示例
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657 | @Slf4j(topic = "c.TestStampedLock")public class TestStampedLock { public static void main(String[] args) { DataContainerStamped dataContainer = new DataContainerStamped(1); new Thread(() -> { dataContainer.read(1); }, "t1").start(); sleep(0.5); new Thread(() -> { dataContainer.read(0); }, "t2").start(); }}@Slf4j(topic = "c.DataContainerStamped")class DataContainerStamped { private int data; private final StampedLock lock = new StampedLock(); public DataContainerStamped(int data) { this.data = data; } public int read(int readTime) { long stamp = lock.tryOptimisticRead(); log.debug("optimistic read locking...{}", stamp); sleep(readTime); if (lock.validate(stamp)) { log.debug("read finish...{}, data:{}", stamp, data); return data; } // 锁升级 - 读锁 log.debug("updating to read lock... {}", stamp); try { stamp = lock.readLock(); log.debug("read lock {}", stamp); sleep(readTime); log.debug("read finish...{}, data:{}", stamp, data); return data; } finally { log.debug("read unlock {}", stamp); lock.unlockRead(stamp); } } public void write(int newData) { long stamp = lock.writeLock(); log.debug("write lock {}", stamp); try { sleep(2); this.data = newData; } finally { log.debug("write unlock {}", stamp); lock.unlockWrite(stamp); } }} |
---|
加锁解锁
123456 | long stamp = lock.tryOptimisticRead(); //乐观读,不阻塞,,读取完毕后需要做一次 戳校验 如果校验通过,表示这期间确实没有写操作,数据可以安全使用,如果校验没通过,需要重新获取读锁,保证数据安全。lock.validate(stamp); //验证时间戳lock.readLock();lock.unlockRead(stamp);lock.writeLock();lock.unlockWrite(stamp); |
---|
Semaphore
信号量为0时阻塞。
12345678910111213141516171819202122232425 | @Slf4j(topic = "c.TestSemaphore")public class TestSemaphore { public static void main(String[] args) { // 1. 创建 semaphore 对象 Semaphore semaphore = new Semaphore(3); // 2. 10个线程同时运行 for (int i = 0; i < 10; i ) { new Thread(() -> { try { semaphore.acquire(); } catch (InterruptedException e) { e.printStackTrace(); } try { log.debug("running..."); sleep(1); log.debug("end..."); } finally { semaphore.release(); } }).start(); } }} |
---|
CountdownLatch
用来进行线程同步协作,等待所有线程完成倒计时。
其中构造参数用来初始化等待计数值,await()
用来等待计数归零,countDown()
用来让计数减一。只有减为0的时候,才停止阻塞,并且计数不可被重置。
1234567891011121314151617181920212223242526 | private static void test2() throws InterruptedException { AtomicInteger num = new AtomicInteger(0); ExecutorService service = Executors.newFixedThreadPool(10, (r) -> { return new Thread(r, "t" num.getAndIncrement()); }); CountDownLatch latch = new CountDownLatch(10); String[] all = new String[10]; Random r = new Random(); for (int j = 0; j < 10; j ) { int x = j; service.submit(() -> { for (int i = 0; i <= 100; i ) { try { Thread.sleep(r.nextInt(100)); } catch (InterruptedException e) { } all[x] = Thread.currentThread().getName() "(" (i "%") ")"; System.out.print("r" Arrays.toString(all)); } latch.countDown(); }); } latch.await(); System.out.println("n游戏开始..."); service.shutdown(); } |
---|
CyclicBarrier
循环栅栏,用来进行线程协作,等待线程满足某个计数。构造时设置计数个数,每个线程执行到某个需要”同步“的时刻调用await()
方法进行等待,当等待的线程数满足计数个数时,继续执行。
CyclicBarrier
与CountDownLatch
的主要区别在于CyclicBarrier
是可以重用的,而CyclicBarrier
可以被比喻为人满发车。
12345678910111213141516171819202122232425262728 | public static void main(String[] args) { ExecutorService service = Executors.newFixedThreadPool(2); CyclicBarrier barrier = new CyclicBarrier(2, ()-> { // 个数为2时才会继续执行 log.debug("task1, task2 finish..."); }); for (int i = 0; i < 3; i ) { // task1 task2 service.submit(() -> { log.debug("task1 begin..."); sleep(1); try { barrier.await(); // 当个数不足时,等待 } catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); } }); service.submit(() -> { log.debug("task2 begin..."); sleep(2); try { barrier.await(); // 2 秒后,线程个数够2,继续运行 } catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); } }); } service.shutdown(); } |
---|