并发总结
该文档从三个方面来总结并发:
一,线程安全
什么是线程安全?
同一段代码多线程运行与单线程运行,每次结果都一样并且结果与预期一致,就是线程安全。换言之多线程并没有导致数据与预期不一致。
简单例子:
不安全的ArrayList添加元素。如果单线程添加元素,没有问题。如果有两个线程添加元素,A线程欲在position=0位置添加数字10,在还没有添加进去时,此时B线程也在添加数据,结果B把position=0位置数据添加为20,此时A线程工作position=0位置数据改为10。与预期不一致,预期ArrayList中有两个数据10,20.现在只有一个数据10。
如何做到线程安全?
synchronized关键字方案:
通过将多线程共享的资源添加一把锁,这样每个线程访问共享资源就都是串行访问,不会出现线程不安全的问题。
synchronized(lock){ doSomething(resource) }
synchronized底层如何实现?
synchronized关键字在字节码层面上将其monitorenter,monitorexit两个成对原语。
二,线程可见性
因为一个系统可能有多颗CPU,为了保证一个线程中对一个变量的修改,在另外一个线程中被看见,所以有了线程可见性的问题。一般采用volatile关键字实现。
三,线程池
Java基础中熟悉一种线程池框架就可以应对工作中90%的场景:Executor框架
/** * Creates a new {@code ThreadPoolExecutor} with the given initial * parameters and default thread factory and rejected execution handler. * It may be more convenient to use one of the {@link Executors} factory * methods instead of this general purpose constructor. * * @param corePoolSize the number of threads to keep in the pool, even * if they are idle, unless {@code allowCoreThreadTimeOut} is set * @param maximumPoolSize the maximum number of threads to allow in the * pool * @param keepAliveTime when the number of threads is greater than * the core, this is the maximum time that excess idle threads * will wait for new tasks before terminating. * @param unit the time unit for the {@code keepAliveTime} argument * @param workQueue the queue to use for holding tasks before they are * executed. This queue will hold only the {@code Runnable} * tasks submitted by the {@code execute} method. * @throws IllegalArgumentException if one of the following holds:<br> * {@code corePoolSize < 0}<br> * {@code keepAliveTime < 0}<br> * {@code maximumPoolSize <= 0}<br> * {@code maximumPoolSize < corePoolSize} * @throws NullPointerException if {@code workQueue} is null */ public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); }
搞懂Executor只需要搞明白上面这个构造函数就可以。
- taskCount<=corePoolSize:用该线程池中缓存的线程去执行task
- taskCount>corePollSize && taskCount<maxPoolSize:新建线程(maxPoolSize-corePoolSize)来应对多余的task
- taskCount>maxPoolSize:多余的task的放到queue中等待,等待时间为keepAliveTime,如果超时采用RejectedExecutionHandler来处理
-
AbortPolicy
-
CallerRunsPolicy
-
DiscardOldestPolicy
-
DiscardPolicy
-
该线程池还是非常清晰明白了。
四,concurrent包内容
该包下都是并发的好东西,拣上面比较重要的总结下
Atomic
满足原子的对各种数据类型的对象进行操作
locks
queue