编程语言
首页 > 编程语言> > 图解Java多线程设计模式》学习笔记(三)Single Threaded Execution模式

图解Java多线程设计模式》学习笔记(三)Single Threaded Execution模式

作者:互联网

一、Single Threaded Execution
二、不使用Single Threaded Execution的程序
1. 场景
2. 代码
// 表示人通过的门
public class Gate {
    // 记录已通过门的人数
    private int counter = 0;
    // 最后一个通过人的姓名
    private String name = "Nobody";
    // 最后一个通过人的出生地
    private String address = "Nowhere";

    // 通过门
    public void pass(String name, String address) {
        this.counter++;
        this.name = name;
        this.address = address;
        check();
    }

    // 当前门的状态
    @Override
    public String toString() {
        return "Gate{" +
                "counter=" + counter +
                ", name='" + name + '\'' +
                ", address='" + address + '\'' +
                '}';
    }

    // 人姓名与出生地首字母不符说明记录异常
    private void check() {
        if (name.charAt(0) != address.charAt(0)) {
            System.out.println("***** BROKEN *****" + toString());
        }
    }
}
public class UserThread extends Thread {
    // 要通过的门
    private final Gate gate;
    // 姓名
    private final String myName;
    // 出生地
    private final String myAddress;

    // 不在字段声明时赋值,在构造函数中初始化字段的形式叫空白final
    public UserThread(Gate gate, String myName, String myAddress) {
        this.gate = gate;
        this.myName = myName;
        this.myAddress = myAddress;
    }

    // 表示这个人不断通过门
    @Override
    public void run() {
        System.out.println(myName + " BEGIN");
        while (true) {
            gate.pass(myName, myAddress);
        }
    }
}
public class Main {
    public static void main(String[] args) {
        System.out.println("Testing Gate,hit CTRL+C to exit.");
        Gate gate = new Gate();
        new UserThread(gate,"Alice","Alaska").start();
        new UserThread(gate,"Bobby","Brazil").start();
        new UserThread(gate,"Chris","Canada").start();
    }
}
Testing Gate,hit CTRL+C to exit.
Alice BEGIN
Chris BEGIN
Bobby BEGIN
***** BROKEN *****Gate{counter=212316276, name='Alice', address='Brazil'}
***** BROKEN *****Gate{counter=212318781, name='Bobby', address='Canada'}
***** BROKEN *****Gate{counter=212321373, name='Bobby', address='Alaska'}
***** BROKEN *****Gate{counter=212322213, name='Bobby', address='Alaska'}
***** BROKEN *****Gate{counter=212322955, name='Bobby', address='Alaska'}
3. 运行结果

程序出错了,说明Gate类是不安全的。

4. 分析原因

pass方法被多个线程执行

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

这四条语句可能是交错执行的

三、使用Single Threaded Execution的程序
package SingleThreadExecution;

/**
 * @author yzy
 * @date 2021/2/23 11:17
 */

// 表示人通过的门
public class Gate {
    // 记录已通过门的人数
    private int counter = 0;
    // 最后一个通过人的姓名
    private String name = "Nobody";
    // 最后一个通过人的出生地
    private String address = "Nowhere";

    // 通过门
    public synchronized void pass(String name, String address) {
        this.counter++;
        this.name = name;
        this.address = address;
        check();
    }

    // 当前门的状态
    @Override
    public synchronized String toString() {
        return "Gate{" +
                "counter=" + counter +
                ", name='" + name + '\'' +
                ", address='" + address + '\'' +
                '}';
    }

    // 人姓名与出生地首字母不符说明记录异常
    private void check() {
        if (name.charAt(0) != address.charAt(0)) {
            System.out.println("***** BROKEN *****" + toString());
        }else{
            System.out.println(this.toString());
        }
    }
}

对pass和toString加上synchronized,这样输出结果正常了。

Testing Gate,hit CTRL+C to exit.
Chris BEGIN
Alice BEGIN
Bobby BEGIN
....
Gate{counter=744937, name='Chris', address='Canada'}
Gate{counter=744938, name='Chris', address='Canada'}
Gate{counter=744939, name='Chris', address='Canada'}
Gate{counter=744940, name='Chris', address='Canada'}
Gate{counter=744941, name='Chris', address='Canada'}
Gate{counter=744942, name='Chris', address='Canada'}
Gate{counter=744943, name='Chris', address='Canada'}
Gate{counter=744944, name='Chris', address='Canada'}
Gate{counter=744945, name='Chris', 
四、Single Threaded Execution中的角色

共享资源(SharedResource):

五、扩展思路
1. 使用场景
2. 生存性与死锁
3. 可用性和继承反常

多线程程序,继承会引起一些麻烦问题,成为继承反常

4. 临界区的大小和性能

一般情况下,Single Threaded Execution模式会降低程序性能,原因如下:

六、延伸
1. synchronized语法与Befor/After模式
synchronize void method(){
    
}
void method(){
    lock();
    
    
    unlock();
}
2. synchronized在保护什么

如Gate中,将pass声明为synchronized,则synchronized就保护着counter,name,address这三个字段。

3. 该以什么单位来保护

若在Gate中加入以下代码:

  public synchronized void setName(String name) {
        this.name = name;
    }

    public synchronized void setAddress(String address) {
        this.address = address;
    }

Gate类就不安全了,将pass声明为synchronized的目的是防止多个线程交错执行赋值操作,而加入两个set方法,则破坏了这个目的。在保护Gate时,要将字段合在一起保护。

4. 原子操作
5. long与double的操作不是原子的
七、总结

标签:设计模式,Java,name,counter,线程,address,Gate,多线程,String
来源: https://www.cnblogs.com/zionyang/p/14436557.html