保护型暂停

代码:
// 增加超时效果class GuardedObject {// 结果private Object response;// 获取结果public Object get() {synchronized (this) {while (response == null) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}return response;}}// 产生结果public void complete() {synchronized (this) {// 给结果成员变量赋值,赋值成功后才唤醒另一个线程this.response = response;this.notifyAll();}}}
优势:
- 比之join,好处是可以异步执行代码
- join必须要定义全局变量,而Guarded Suspension可以用局部变量
终止模式之两阶段终止模式
在一个线程T1中,如何优雅终止线程T2?
这里的【优雅】指的是给T2正常关闭的时间。
思路:
- interrupt
- volatile
@Slf4j(topic = "c.TwoPhaseTermination")class TwoPhaseTermination {// 监控线程private Thread monitorThread;// 停止标记(使用volatile,确保可见性,监控线程在循环的时候仍然可以看到值被修改)private volatile boolean stop = false;// 判断是否执行过 start 方法private boolean starting = false;// 启动监控线程public void start() {synchronized (this) {if (starting) { // falsereturn;}starting = true;}monitorThread = new Thread(() -> {while (true) {Thread current = Thread.currentThread();// 是否被打断if (stop) {log.debug("料理后事");break;}try {Thread.sleep(1000);log.debug("执行监控记录");} catch (InterruptedException e) {}}}, "monitor");monitorThread.start();}// 停止监控线程public void stop() {stop = true;monitorThread.interrupt();}}
单例模式
很多场景都会用到单例模式,但是多并发下的单例模式会有很多问题发生
先看看一个线程不安全的:
public final class Singleton {private Singleton() { }private static Singleton INSTANCE = null;// 分析这里的线程安全, 并说明有什么缺点public static synchronized Singleton getInstance() {if( INSTANCE != null ){return INSTANCE;}INSTANCE = new Singleton();return INSTANCE;}}
- synchronize的范围太大,影响性能
- INSTANCE并没有加volatile,可能会导致指令重排
改进
public final class Singleton {private Singleton() { }// 加 volatileprivate static volatile Singleton INSTANCE = null;// 要点1public static Singleton getInstance() {if (INSTANCE != null) {return INSTANCE;}synchronized (Singleton.class) {// 要点2:为什么还要在这里加为空判断,上面不是判断过了吗if (INSTANCE != null) {return INSTANCE;}INSTANCE = new Singleton();return INSTANCE;}}}
- 要点1:将方法上的synchronize卸下,将锁细化
- 要点2:防止第一次初始化时,有多个线程进入,从而对上一个线程创建的单例对象进行覆盖赋值
- 这个也叫DCL懒汉式(双重监测懒汉式),缩小了锁的范围,只有第一次会进入创建对象的方法,提高了效率。
推荐方法:
public final class Singleton {private Singleton() { }// 问题1:属于懒汉式还是饿汉式private static class LazyHolder {static final Singleton INSTANCE = new Singleton();}// 问题2:在创建时是否有并发问题public static Singleton getInstance() {return LazyHolder.INSTANCE;}}
- 问题一:静态内部类,只有当使用到的时候才会创建,所以是懒汉式
- 问题二:静态方法会随着静态类加载,是由JVM负责,所以没有并发问题
异步模式之工作线程
让有限的工作线程(Worker Thread)来轮流异步处理无限多的任务。也可以将其归类为分工模式,它的典型实现 就是线程池,也体现了经典设计模式中的享元模式
但注意,当线程池中线程设置为固定大小时,会发生饥饿问题,如何解决?
- 不同的任务类型,采用不同的线程
- 创建合适的线程数量
而如何创建合适的线程数量又是一个问题,根据线程的不同任务可大体分为两种
- IO密集型
- CPU密集型
