Java内存模型之可见性

 这段代码无法退出循环?

@Slf4j
public class juc14 {
    static boolean flag = true;

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            while(flag) {
                // ...
            }
        }).start();
        
        Thread.sleep(1000);
        
        log.info("停止");
        
        flag = false;
    }
}

分析

 

解决方法:

方法一:

volatile static boolean flag = true;

volatile(易变关键字)

        它可以用来修饰成员变量和静态成员变量,他可以避免线程从自己的工作缓存中查找变量的值,必须到主存中获取它的值,线程操作volatile变量都是直接操作主存

方法二:

synchronized

@Slf4j
public class juc14 {
    static boolean flag = true;
    final static Object lock = new Object();

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            while(true) {
                synchronized (lock) {
                    if(!flag){
                        break;
                    }
                }
            }
        }).start();

        Thread.sleep(1000);

        log.info("停止");

        synchronized (lock){
            flag = false;
        }
    }
}

 保证可见性一般推荐volatile,较synchronized更轻量级

注意
        synchronized语句块既可以保证代码块的原子性,也同时保证代码块内变量的可见性。但缺点是synchronized是属于重量级操作,性能相对更低
        如果在前面示例的死循环中加入 System.out.println()会发现即使不加volatile修饰符,线程t也能正确看到对run变量的修改了,想一想为什么?I
 

用volatile改进两阶段终止代码

 

/**
 * 两阶段终止改进
 */
@Slf4j
class TwoStateTerminatedImprove {
    private Thread monitorThread;
    private volatile boolean stop = false;

    public void start() {
        monitorThread = new Thread(() -> {
            while (true) {
                Thread t = Thread.currentThread();
                if (stop) {
                    log.info("料理后事");
                    break;
                }
                try {
                    Thread.sleep(500);
                    log.info("执行监控代码");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"monitor");
        monitorThread.start();
    }

    public void stop() {
        stop = true;
        monitorThread.interrupt();
    }
}

@Slf4j
class test01 {
    public static void main(String[] args) {
        TwoStateTerminatedImprove tstp = new TwoStateTerminatedImprove();
        tstp.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        log.info("停止监控");
        tstp.stop();
    }
}

 

Balking模式

/**
 * ==============================================================
 * Balking 犹豫模式
 *
 * 定义:Balking (犹豫)模式用在一个线程发现另一个线程或本线程已经做了某一件相同的事,
 * 那么本线程就无需再做了,直接结束返回
 *
 * 场景:  1. 保证监控线程只启动一次
 */
@Slf4j
class HesitatePattern {
    private Thread monitorThread;
    private volatile boolean stop = false;

    // 是否调用过start(),保证只调用一次start
    private boolean started = false;

    public void start() {
        synchronized (this) {
            if (started) {
                return;
            }
            started = true;
        }
        monitorThread = new Thread(() -> {
            while (true) {
                Thread t = Thread.currentThread();
                if (stop) {
                    log.info("料理后事");
                    break;
                }
                try {
                    Thread.sleep(500);
                    log.info("执行监控代码");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "monitor");
        monitorThread.start();
    }

    public void stop() {
        stop = true;
        monitorThread.interrupt();
    }
}

@Slf4j
class test02 {
    public static void main(String[] args) {
        HesitatePattern hp = new HesitatePattern();
        hp.start();
        hp.start();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZuckD

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值