学习
https://time.geekbang.org/column/article/83267
https://time.geekbang.org/column/article/83087
并发编程有三个核心的问题
1、分工
指的是如何高效地拆解任务并分配给线程,Java SDK 并发包里的 Executor、Fork/Join、Future 本质上都是一种分工方法。除此之外,并发编程领域还总结了一些设计模式,基本上都是和分工方法相关的,例如生产者 - 消费者、Thread-Per-Message、Worker Thread 模式等都是用来指导你如何分工的。
2、同步
分工之后就要考虑多个线程如何执行,期间就涉及到了同步
同步可以总结为:当某个条件不满足时,线程需要等待,当某个条件满足时,线程需要被唤醒执行
例如,在生产者 - 消费者模型里,也有类似的描述,“当队列满时,生产者线程等待,当队列不满时,生产者线程需要被唤醒执行;当队列空时,消费者线程等待,当队列不空时,消费者线程需要被唤醒执行。”
3、互斥
分工、同步主要强调的是性能,但是我们还要保证正确性,也就是线程安全,
保证同一时刻只允许一个线程访问共享资源
并发程序里,当多个线程同时访问同一个共享变量的时候,结果是不确定的。不确定,则意味着可能正确,也可能错误,事先是不知道的。M而导致不确定的主要源头是可见性问题、有序性问题和原子性问题,为了解决这三个问题引入了JMM
解决互斥基本使用的是加锁, synchronized、SDK 里的各种 Lock 都能解决互斥问题。虽说锁解决了安全性问题,但同时也带来了性能问题
但是也有其他的方案避免因为共享变量导致线程安全问题,比如Thread Local 和 final 关键字,还有一种 Copy-on-write 的模式。
扩展
- 什么场景下使用CountDownLatch
比如多线程解析excel的多个sheet,可以开启多个线程去解析,每个线程解析一个sheet,解析完成之后执行countDown方法,在最后执行await()方法,直到所有线程执行完成
参考自https://ifeve.com/talk-concurrency-countdownlatch/
- countDown代码演示 相当于一场考试。所有的学生交了试卷之后,老师才开始离开教师.
代码来自https://www.cnblogs.com/bqcoder/p/6089101.html
public static void testCountDownLatch(){int threadCount = 10;final CountDownLatch latch = new CountDownLatch(threadCount);for(int i=0; i< threadCount; i++){new Thread(()->{System.out.println("线程" + Thread.currentThread().getId() + "开始出发");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程" + Thread.currentThread().getId() + "已到达终点");latch.countDown();}).start();}try {//会等待所有的线程执行完毕latch.await();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("10个线程已经执行完毕!开始计算排名");}
final 关键字和多线程的关系(happens-before原则)
public class FinalTest {int i;//普通变量final int j;static FinalTest obj;public FinalTest(){i = 1;j = 2;}public static void writer(){obj = new FinalTest();}public static void reader(){FinalTest tets = obj;//读对象引用int a = tets.i;//a 和b 不一定等于1,2 因为会有构造函数溢出的可能。int b = tets.j;}}

