ReentrantLock内部包含了一个AQS对象,也就是AbstractQueuedSynchronizer类型的对象。这个AQS对象就是ReentrantLock可以实现加锁和释放锁的关键性的核心组件。
线程A,B尝试进行加锁的过程:
/** * @Author:daboluo * @Date: 2019/9/29 8:58 * @Version 1.0 * * * ReentrantCountExample对count进行相加 */ public class ReentrantCountExample { private static int clientTotal = 5000; private static int threadTotal = 200; private static int count = 0; private static ReentrantLock reentrantLock = new ReentrantLock(); public static void main(String[] args) throws Exception{ ExecutorService exec = Executors.newCachedThreadPool(); final Semaphore semaphore = new Semaphore(threadTotal); for (int i = 0; i < clientTotal; i++) { exec.execute(()->{ try { semaphore.acquire(); add(); semaphore.release(); } catch (InterruptedException e) { e.printStackTrace(); } }); } Thread.sleep(5); exec.shutdown(); System.out.println("count = " + count); } /** * * synchronized : 不可中断的,适合竞争不激烈的,可见性 * lock: 可中断锁,多样化同步,竞争激烈时能维持常态 * atomic:竞争激烈时能维持常态,比lock的性能更佳,能同步一个值 * * */ private static void add(){ reentrantLock.lock(); count++; reentrantLock.unlock(); } }
结果:
count = 5000
CountDownLatch应用场景:线程协调使用的时减法操作,用于并行计算的时候,如果某一个处理过程运算量特别大,可以将这个任务拆分成很多个小的子任务,等待所有子任务计算完,父任务再拿到所有子任务进行汇总,降低处理时间。
/** * @Author:daboluo * @Date: 2019/9/29 22:45 * @Version 1.0 * * * 并行计算,计算量很大,直接拆分成子线程,最后,进行汇总 */ public class CountDownLatchDemo { private static CountDownLatch countDownLatch = new CountDownLatch(100); private static Long count = 0L; public static void main(String[] args) throws Exception { ExecutorService exec = Executors.newCachedThreadPool(); for (int i = 0; i < 100; i++) { exec.execute(() -> { try { test(); } finally { countDownLatch.countDown(); } }); } countDownLatch.await(); System.out.println("finish : count = " + count); } public static void test() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } count++; System.out.println(count); } }
结果:
。。。
96
97
95
finish : count = 100
CyclicBarrier应用场景:线程协调使用的时加法操作,有针对出现异常的reset方法,用于统计一年的excel数据,可以开多个线程统计每一页的数据,然后再进行汇总
/** * @Author:daboluo * @Date: 2019/9/29 22:45 * @Version 1.0 * * 在excel表统计银行的日均流水,每一页的日均银行流水,在计算年的流水 * * cyclic计算错误的时候,可以进行reset, */ public class CyclicBarrierDemo { // 可以设置内存达到屏障的时候,直接打印 private static CyclicBarrier cyclicBarrier = new CyclicBarrier(5); public static void main(String[] args) throws Exception{ ExecutorService exec = Executors.newCachedThreadPool(); for(int i=0;i<10;i++){ final int threadNum = i; Thread.sleep(1000); exec.execute(()->{ try { test(threadNum); } catch (Exception e) { e.printStackTrace(); }finally { } }); } exec.shutdown(); } public static void test(int a ) throws Exception{ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(" ready-----" + a); cyclicBarrier.await(); System.out.println(" continue-----" + a); } /** * ready-----0 ready-----1 ready-----2 ready-----3 ready-----4 continue-----4 continue-----0 continue-----1 continue-----2 continue-----3 ready-----5 ready-----6 ready-----7 ready-----8 ready-----9 continue-----9 continue-----5 continue-----7 continue-----6 continue-----8 */ }