java編碼:保證方法呼叫鏈的原子性

jhjswe發表於2020-12-27

保證方法呼叫鏈的原子性

如果我們想建立一個物件的例項,而這個物件的例項是通過鏈式呼叫建立的。然後我們需要保證鏈呼叫的原子性。

請考慮以下示例:

public class ChainedMethod {
private int age=0;
private String name="";
private String adress="";

public ChainedMethod setAdress(String adress) {
    this.adress = adress;
    return this;
}

public ChainedMethod setAge(int age) {
    this.age = age;
    return this;
}

public ChainedMethod setName(String name) {
    this.name = name;
    return this;
}

}

一個非常簡單的物件,我們定義了三個屬性,每個時間集返回一個對此的引用。
https://club.lenovo.com.cn/thread-6601546-1-1.html
https://club.lenovo.com.cn/thread-6601557-1-1.html
https://club.lenovo.com.cn/thread-6601570-1-1.html
https://club.lenovo.com.cn/thread-6601817-1-1.html
https://club.lenovo.com.cn/thread-6601839-1-1.html
https://club.lenovo.com.cn/thread-6601855-1-1.html
https://club.lenovo.com.cn/thread-6601867-1-1.html
https://club.lenovo.com.cn/thread-6601882-1-1.html
https://club.lenovo.com.cn/thread-6601897-1-1.html
https://club.lenovo.com.cn/thread-6601916-1-1.html
https://club.lenovo.com.cn/thread-6601933-1-1.html
https://club.lenovo.com.cn/thread-6601984-1-1.html
https://club.lenovo.com.cn/thread-6601999-1-1.html
https://club.lenovo.com.cn/thread-6602020-1-1.html
https://club.lenovo.com.cn/thread-6602060-1-1.html
https://club.lenovo.com.cn/thread-6602088-1-1.html
https://club.lenovo.com.cn/thread-6602105-1-1.html
https://club.lenovo.com.cn/thread-6602117-1-1.html
https://club.lenovo.com.cn/thread-6602372-1-1.html
https://club.lenovo.com.cn/thread-6602396-1-1.html
https://club.lenovo.com.cn/thread-6602406-1-1.html
https://club.lenovo.com.cn/thread-6602417-1-1.html
https://club.lenovo.com.cn/thread-6602427-1-1.html
https://club.lenovo.com.cn/thread-6602435-1-1.html
https://club.lenovo.com.cn/thread-6602446-1-1.html
https://club.lenovo.com.cn/thread-6602467-1-1.html
https://club.lenovo.com.cn/thread-6602504-1-1.html
https://club.lenovo.com.cn/thread-6602520-1-1.html
https://club.lenovo.com.cn/thread-6602553-1-1.html
https://club.lenovo.com.cn/thread-6602591-1-1.html
https://club.lenovo.com.cn/thread-6602610-1-1.html
https://club.lenovo.com.cn/thread-6602623-1-1.html
https://club.lenovo.com.cn/thread-6602633-1-1.html
https://club.lenovo.com.cn/thread-6603123-1-1.html
https://club.lenovo.com.cn/thread-6603204-1-1.html
https://club.lenovo.com.cn/thread-6603239-1-1.html
https://club.lenovo.com.cn/thread-6603278-1-1.html
https://club.lenovo.com.cn/thread-6603319-1-1.html
https://club.lenovo.com.cn/thread-6603342-1-1.html
https://club.lenovo.com.cn/thread-6603371-1-1.html
https://club.lenovo.com.cn/thread-6603421-1-1.html
https://club.lenovo.com.cn/thread-6603494-1-1.html
https://club.lenovo.com.cn/thread-6603513-1-1.html
https://club.lenovo.com.cn/thread-6603572-1-1.html
https://club.lenovo.com.cn/thread-6603643-1-1.html
https://club.lenovo.com.cn/thread-6603688-1-1.html
https://club.lenovo.com.cn/thread-6603969-1-1.html
https://club.lenovo.com.cn/thread-6603984-1-1.html
https://club.lenovo.com.cn/thread-6604101-1-1.html
https://club.lenovo.com.cn/thread-6604188-1-1.html
https://club.lenovo.com.cn/thread-6604203-1-1.html
https://club.lenovo.com.cn/thread-6604226-1-1.html
https://club.lenovo.com.cn/thread-6604266-1-1.html
https://club.lenovo.com.cn/thread-6604297-1-1.html
https://club.lenovo.com.cn/thread-6604321-1-1.html
https://club.lenovo.com.cn/thread-6604351-1-1.html
https://club.lenovo.com.cn/thread-6604456-1-1.html
https://club.lenovo.com.cn/thread-6604482-1-1.html
https://club.lenovo.com.cn/thread-6604542-1-1.html
https://club.lenovo.com.cn/thread-6604644-1-1.html
https://club.lenovo.com.cn/thread-6604706-1-1.html
https://club.lenovo.com.cn/thread-6604983-1-1.html
https://club.lenovo.com.cn/thread-6604998-1-1.html
https://club.lenovo.com.cn/thread-6605111-1-1.html
https://club.lenovo.com.cn/thread-6605152-1-1.html
https://club.lenovo.com.cn/thread-6605172-1-1.html
https://club.lenovo.com.cn/thread-6605190-1-1.html
https://club.lenovo.com.cn/thread-6605207-1-1.html
https://club.lenovo.com.cn/thread-6605226-1-1.html
https://club.lenovo.com.cn/thread-6605254-1-1.html
https://club.lenovo.com.cn/thread-6605288-1-1.html
https://club.lenovo.com.cn/thread-6605357-1-1.html
https://club.lenovo.com.cn/thread-6605388-1-1.html
https://club.lenovo.com.cn/thread-6605423-1-1.html
https://club.lenovo.com.cn/thread-6605468-1-1.html
https://club.lenovo.com.cn/thread-6605513-1-1.html
https://club.lenovo.com.cn/thread-6605988-1-1.html
https://club.lenovo.com.cn/thread-6606015-1-1.html
https://club.lenovo.com.cn/thread-6606203-1-1.html
https://club.lenovo.com.cn/thread-6606251-1-1.html
https://club.lenovo.com.cn/thread-6606260-1-1.html
https://club.lenovo.com.cn/thread-6606274-1-1.html
https://club.lenovo.com.cn/thread-6606287-1-1.html
https://club.lenovo.com.cn/thread-6606300-1-1.html
https://club.lenovo.com.cn/thread-6606316-1-1.html
https://club.lenovo.com.cn/thread-6606359-1-1.html
https://club.lenovo.com.cn/thread-6606422-1-1.html
https://club.lenovo.com.cn/thread-6606445-1-1.html
https://club.lenovo.com.cn/thread-6606477-1-1.html
https://club.lenovo.com.cn/thread-6606521-1-1.html
https://club.lenovo.com.cn/thread-6606541-1-1.html
https://club.lenovo.com.cn/thread-6606934-1-1.html
https://club.lenovo.com.cn/thread-6606957-1-1.html
https://club.lenovo.com.cn/thread-6607669-1-1.html
https://club.lenovo.com.cn/thread-6607696-1-1.html
https://club.lenovo.com.cn/thread-6607711-1-1.html
https://club.lenovo.com.cn/thread-6607721-1-1.html
https://club.lenovo.com.cn/thread-6607729-1-1.html
https://club.lenovo.com.cn/thread-6607737-1-1.html
https://club.lenovo.com.cn/thread-6607749-1-1.html
https://club.lenovo.com.cn/thread-6607764-1-1.html
https://club.lenovo.com.cn/thread-6607773-1-1.html
https://club.lenovo.com.cn/thread-6607790-1-1.html
https://club.lenovo.com.cn/thread-6607804-1-1.html
https://club.lenovo.com.cn/thread-6607820-1-1.html
https://club.lenovo.com.cn/thread-6607836-1-1.html
https://club.lenovo.com.cn/thread-6608067-1-1.html
https://club.lenovo.com.cn/thread-6608103-1-1.html
https://mclub.lenovo.com.cn/thread-6592866-1-1.html
https://mclub.lenovo.com.cn/thread-6594212-1-1.html
https://mclub.lenovo.com.cn/thread-6594213-1-1.html
https://mclub.lenovo.com.cn/thread-6594216-1-1.html
https://mclub.lenovo.com.cn/thread-6594217-1-1.html
https://mclub.lenovo.com.cn/thread-6594220-1-1.html
https://mclub.lenovo.com.cn/thread-6594335-1-1.html
https://mclub.lenovo.com.cn/thread-6594337-1-1.html
https://mclub.lenovo.com.cn/thread-6594342-1-1.html
https://mclub.lenovo.com.cn/thread-6594344-1-1.html
https://mclub.lenovo.com.cn/thread-6594349-1-1.html
https://mclub.lenovo.com.cn/thread-6594353-1-1.html
讓我們看看如何在多執行緒環境中呼叫:

    ChainedMethod chainedMethod= new ChainedMethod();
    Thread t1 = new Thread(() -> chainedMethod.setAge(1).setAdress("www").setName("name1"));
    t1.start();

    Thread t2 = new Thread(() -> chainedMethod.setAge(2).setAdress("www2").setName("name2"));
    t2.start();

因為在多執行緒環境下,上面設定的方法可能會比較混亂。怎麼解決?我們可以首先建立一個本地副本,這是執行緒安全的,因為它是在本地訪問的,最後將副本複製到新建立的例項物件。

主要程式碼如下:
public class ChainedMethodWithBuilder {
private int age=0;
private String name="";
private String adress="";

public ChainedMethodWithBuilder(Builder builder){
    this.adress=builder.adress;
    this.age=builder.age;
    this.name=builder.name;
}

public static class Builder{
    private int age=0;
    private String name="";
    private String adress="";

    public static Builder newInstance(){
        return new Builder();
    }
    private Builder() {}

    public Builder setName(String name) {
        this.name = name;
        return this;
    }

    public Builder setAge(int age) {
        this.age = age;
        return this;
    }

    public Builder setAdress(String adress) {
        this.adress = adress;
        return this;
    }

    public ChainedMethodWithBuilder build(){
        return new ChainedMethodWithBuilder(this);
    }
}

我們看下怎麼呼叫:
  final ChainedMethodWithBuilder[] builder = new ChainedMethodWithBuilder[1];
    Thread t1 = new Thread(() -> {
        builder[0] =ChainedMethodWithBuilder.Builder.newInstance()
            .setAge(1).setAdress("www").setName("name1")
            .build();});
    t1.start();

    Thread t2 = new Thread(() ->{
        builder[0] =ChainedMethodWithBuilder.Builder.newInstance()
            .setAge(1).setAdress("www").setName("name1")
            .build();});
    t2.start();

因為lambda表示式中使用的變數必須是最終的或最終等價的,所以我們需要構建一個最終陣列。

讀寫64bits的值

在java中,64位長和double被視為兩個32位。

因此,64位的一個操作被分成32位的兩個操作。這就導致了原子問題。

請考慮以下程式碼:

public class LongUsage {
private long i =0;

public void setLong(long i){
    this.i=i;
}
public void printLong(){
    System.out.println("i="+i);
}

}

因為long的讀寫分為兩部分,如果在多執行緒環境中多次呼叫setLong和printLong的方法,可能會出現問題。

解決方法很簡單,長變數或雙變數都可以定義為volatile。

private volatile long i = 0;

相關文章