前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JUC内置锁

JUC内置锁

作者头像
兜兜转转
发布2023-03-06 15:11:12
1300
发布2023-03-06 15:11:12
举报
文章被收录于专栏:CodeTime

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()方法进行等待,当等待的线程数满足计数个数时,继续执行。

CyclicBarrierCountDownLatch的主要区别在于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(); }

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-01-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ReentrantReadWriteLock
  • StampedLock
  • Semaphore
  • CountdownLatch
  • CyclicBarrier
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档