JAVA多线程设计模式篇 2、Single Threaded Execution 模式——这一刻,我的眼里只有你

1.孙悟空去了高老庄?

悟空、八戒跟师父请假要回去探亲。师父要求每个人请假要填上姓名、目的地。
弟子们很老实遵照执行,然而,当过了一段时间出了问题。我们看看问题出在哪里。

1.1 定义师父类

师父提供了一个方法 请假(姓名,目的地),即public void notice(String name, String address)。为避免出错,师父类定义了一个私有检查方法,看请假的情况有没有问题。

public class Master {
    private int cnt = 0;
    private String name;
    private String address;

    public synchronized void notice(String name, String address) {
        this.name = name;
        this.address = address;
        cnt++;
        check();
    }

    private void check() {
        if (name.equals("孙悟空") && (!address.equals("花果山")))
            System.out.println("第"+cnt+" 次出现问题:" + name + "," + address);
        if (name.equals("猪八戒") && (!address.equals("高老庄")))
            System.out.println("第"+cnt+" 次出现问题:" + name + "," + address);
    }
}

1.2 定义徒弟类

徒弟很老实,在定义自己信息的时候都用上了final,担心数据被篡改。
徒弟线程类启动后将不断向师父请假。

public class Follower extends Thread {

    private final Master master;
    private final String name;
    private final String address;

    public Follower(Master master,String name,String address){
        this.master = master;
        this.name = name;
        this.address = address;
    }

    @Override
    public void run() {
        while (true) {
            master.notice(name,address);
        }
    }
}

1.3 师父发现不对劲了

在运行过程中,师父的check()方法,发现了不一致的情况。

public class Main {
    public static void main(String[] args) {
        Master master = new Master();
        Follower sunwukong = new Follower(master,"孙悟空","花果山");
        Follower zhubajie = new Follower(master,"猪八戒","高老庄");
        sunwukong.start();
        zhubajie.start();
    }
}

运行结果:

第379950712 次出现问题:孙悟空,花果山
第379956315 次出现问题:孙悟空,高老庄

2.问题出现在哪?

经过一番检查。我们发现Master类是不安全的。

    1. 出现问题:孙悟空,花果山 。这个是正常的啊。为什么还是报错?
    1. 出现问题:孙悟空,高老庄 这个又是怎么产生的呢,明明悟空类的地址是花果山啊。

2.1 问题

观察这几个代码,由于没有同步机制,在多线程环境中是交替执行的,也就是说A B 线程会不断有可能交替覆盖name和address属性。

        this.name = name;
        this.address = address;
        cnt++;
        check();

2.2 完善

将Master的public void notice(String name, String address) 方法更改为同步方法。
经过synchronized方法同步后,出问题的四行代码被打包为一个原子方法。一次性只允许一个徒弟请假,请假的过程中不会出现交替运行的情况,

public synchronized void notice(String name, String address) 

运行很久都没有报错。

2.3 问题二

为什么check方法不需要增加synchronized同步?
因为第一、check()只被notice()调用,而notice方法已经同步了。第二、check()是私有方法,外部无法调用,且内部就只被notice()调用。

3.注意事项

在Single Threaded Execution 模式中,需要仔细找出实例状态不稳定的范围,将这个范围设置为临界区进行保护,同一时间只允许一个线程执行。

总结

在使用多线程环境中,如果共享资源的状态有可能会发生变化,那么更改资源状态的方法很可能就是不安全方法。对于这些方法应该加锁同步,加以保护。

多线程系列在github上有一个开源项目,本系列博客的实验代码都在里面。

https://github.com/forestnlp/concurrentlab

如果您对软件开发、机器学习、深度学习有兴趣请关注本博客,将持续推出Java、软件架构、深度学习相关专栏。

您的支持是对我最大的鼓励。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

悟空学编程

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

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

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

打赏作者

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

抵扣说明:

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

余额充值