JUC类小结

本文深入探讨了可重入锁的设计原因及其应用场景,包括ReentrantLock、CountDownLatch与CyclicBarrier等并发工具类,并对比了JDK1.7与JDK1.8中ConcurrentHashMap的不同实现方式。

1.为什么要设计可重入锁?
**当方法A拥有一个对象锁,而方法B也拥有一个对象锁,当方法B调用方法A时如果锁不是可重入的,那么此时就会发生死锁,所以设计可重入锁就是为了防止死锁。

  1. ReentrantLock:信号量,实现限流,调用acquire方法…
    **CountDownLouch:计数器(自定义初始值),每次调用countDown方法,计数器减一,当计数器减到0时,会执行await后面的代码。该计数器是一次性的,用完不会重置
    **CyclicBarrier:循环屏障:与CountDownLouch相同,但是计数器减到0会重置为初始值,可多次使用

  2. ConcurrentHashMap在JDK1.7使用的是分段锁,而JDK1.8采用CAS+volatile保证线程安全。

  3. ConcurrentHashMap:
    **JDK1.7使用segments数组+HashEntry(key,value)+链表,使用分段锁,每把锁只锁定容器中一部分数据,当多个线程访问不同数据段就不会发生锁竞争。提高并发效率。segments中包含了segment[i],每个segment[i]中有多个HashEntry,每个HashEntry包含一个key和链表的头结点。因为分段的原因,put和get需要进行二次哈希定位具体元素,首先定位在那个segment[i]中,再找具体的值。
    **JDK1.8使用synchronized+CAS+数组+节点+红黑树,只使用synchronized同步put方法中的代码块,get无需加锁。当put元素时,会先使用CAS去插入元素,如果CAS失败才会加synchronized锁。特殊点,当数组为空put元素时直接进入CAS插入值。

5.Unsafe类,Java程序本来是注重安全的语言,程序员不可以直接操作系统内存资源,但是Unsafe类给程序员开了一个后门可直接操作内存,使得Java也拥有了像C指针一样操作内存空间的能力,增加了指针问题带来的风险,如操作堆外内存垃圾回收不及时造成的内存泄漏,compareAndSwap是Unsafe一个重要方法,也是CAS操作。Unsafe类使用单例模式,通过getUnsafe获取静态实例。

### Java JUC 并发包中的同步工具 #### CountDownLatch 的使用方法 `CountDownLatch` 是一种同步辅助,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。此计数器无法重新设置;也就是说,当计数值达到零时,不可以通过任何方式将其重置为更大的值[^2]。 ```java import java.util.concurrent.CountDownLatch; public class Test { public static void main(String[] args) throws InterruptedException { int threadCount = 5; final CountDownLatch countDownLatch = new CountDownLatch(threadCount); for (int i = 0; i < threadCount; ++i){ new Thread(() ->{ try { System.out.println(Thread.currentThread().getName() + " is working"); Thread.sleep(1000); // Simulate work being done. System.out.println(Thread.currentThread().getName() + " finished."); } catch (InterruptedException e) { e.printStackTrace(); } countDownLatch.countDown(); // Decrements the count of the latch, releasing all waiting threads if the count reaches zero. }).start(); } countDownLatch.await(); // Blocks until the count reaches zero due to invocations of the `countDown()` method from other threads. System.out.println("All tasks are completed!"); } } ``` #### CyclicBarrier 的使用方法 `CyclicBarrier` 支持一定数量的线程彼此之间互相等待,一旦达到了指定的数量,则可以继续执行后续的任务。与 `CountDownLatch` 不同的是,它可以重复利用已设定好的状态[^4]。 ```java import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; class Task implements Runnable { private CyclicBarrier cb; public Task(CyclicBarrier cb) { this.cb = cb; } @Override public void run() { try { System.out.println(Thread.currentThread().getName() + ": 已经到达障碍点,正在等待..."); cb.await(); // 所有参与者都已经抵达屏障处后要做的工作... System.out.println(Thread.currentThread().getName() + ": 继续前进!"); } catch (InterruptedException | BrokenBarrierException ex) { ex.printStackTrace(); } } } public class BarrierExample { public static void main(String[] args) { int parties = 3; CyclicBarrier barrier = new CyclicBarrier(parties); for(int i=0;i<parties;++i) new Thread(new Task(barrier)).start(); } } ``` #### Semaphore 的使用方法 信号量用于控制访问特定资源的线程数目,它维护了一个许可集合。如有必要,在许可可用前会阻塞每一个 acquire 方法,然后再获取该许可。每个 release 方法都会返回一个许可,从而可能释放一个阻塞的 acquire。 ```java import java.util.concurrent.Semaphore; public class LimitedResourceAccess { private static final int MAX_PERMITS = 3; public static void main(String[] args) { Semaphore semaphore = new Semaphore(MAX_PERMITS); for (int i = 0; i < 6; ++i) { // More requests than permits available. new Thread(() -> { try { semaphore.acquire(); // Acquire a permit before accessing resource. String name = Thread.currentThread().getName(); System.out.printf("%s acquired access.\n", name); Thread.sleep((long)(Math.random()*1000)); // Simulating time spent using resources System.out.printf("%s released access.\n", name); semaphore.release(); // Release the permit after finishing with resource. } catch (InterruptedException ie) {} }, "Thread-" + i).start(); } } } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值