1、挖掘可并发点
2、分而治之
1、基于数据的分割实现并发化
2、基于任务的分割实现并发化
3、合理设置线程数
1、多线程程序的提速只要来自多个线程对程序中可并行化部分的耗时均摊
2、最终决定多线程程序提速的因素是整个计算中串行部分的耗时比率而不是线程数
3、CPU密集型线程,线程数通常设置为N(cpu)+1;I/O密集型线程优先考虑线程数设为1,不够用的情况下将线程数向2*N(cpu)靠近
4、常见的考虑因素:处理器数目、任务的性质、资源使用规划、稀缺资源使用情况
1、wait/notify
1、Object.wait():暂停;Object.notify():唤醒。
使用Java中任何对象都能够实现等待和通知
2、等待线程对保护条件的判断、Object.wait()的调用总是应该放在相应对象所引导的临界区中的一个循环语句之中
3、等待线程对保护条件的判断、Object.wait()的执行以及目标动作的执行必须放在同一个对象(内部锁)所引导的临界区之中
4、Object.wait()暂停当前线程时所释放的锁只是与该wait方法所属对象的内部锁。当前线程所持有的其他内部锁、显式锁并不会被释放
5、调用一个对象的notify方法所唤醒的线程仅是该对象上的任意一个等待线程
6、Java虚拟机会为每个对象维护一个入口集(Entry Set)用于存储申请该对象内部锁的线程;还为每个对象维护一个等待集(Wait Set)的队列用于存储该对象上的等待线程
7、开销/问题
- 过早唤醒—可以利用
java.util.concurrent.locks.Condition
接口解决 - 信号丢失—在必要的时候使用notifyiAll()来通知
- 欺骗性唤醒
- 上下文切换问题
8、使用notify代替notifyAll的条件:
- 一次通知仅需要唤醒至多一个线程
- 相应对象上的所有等待线程都是同质等待的线程
9、Thread.join():当前线程等待目标县城结束之后继续运行
- join(long)版本允许设置一个超时时间,实际上是使用wait/notify实现
2、Java条件变量
Condition
3、倒计时协调器:CountDownLatch
1、CountDownLatch:用来实现一个或者多个线程等待其他线程完成一组特定的操作之后才继续运行(先决操作)
CountDownLatch内部计数器值达到0后其值就恒定不变,后续执行该CountDownLatch实例的await方法的任何一个线程都不会被暂停。为避免等待线程被永久暂停,CountDownLatch.countDown()
调用必须放在代码中总是可以被执行到的地方,如finally块中
4、栅栏CyclicBarrier
1、CyclicBarrier内部维护了一个显式锁,使得其总是可以区分出最后执行等待的线程,最后一个线程执行等待会使得其他执行过等待的线程被唤醒
2、典型应用场景
- 使迭代算法并发化
- 在测试代码中模拟高并发
5、生产者–消费者模式
1、阻塞队列
可以直接使用线程安全的BlockingQueue
作为传输管道
2、流量控制和信号量(Semaphore)
1、流量控制避免在传输通道积压过多产品
2、java.util.concurrent.Semaphore
实现流量控制
3、Semaphore.acquire()
和Semaphore.release()
总是配对使用;Semaphore.release()
调用总是放在一个finally块中,避免出现异常当前线程所获得的配额无法返还
6、线程中断机制
1、Java平台会为每个线程维护一个中断标记(Interrupt Status)的布尔型状态变量用于表示相应线程是否收到中断
2、目标线程对中断的响应:
- 不理会
InputStream.read()
、ReentrantLock.lock()
- 取消任务的运行
取消当前任务,但不影响该线程的其他任务 - 线程停止