單例中的線程不安全性

一、單例設計模式(懶漢式)中的線程不安全問題
看之前寫過的一個單例

public class SingleTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Single s1 = Single.getInstance();
        Single s2 = Single.getInstance();
        System.out.println(s1==s2);
    }

}
class Single{
    private Single() {
    }
    private  static Single s = null;
    public static Single getInstance(){
        if(s==null){
            s = new Single(); 
        }
        return s;
    }
} 

在多線程情況下,上面的單例會出現多次判斷的問題。如果直接在getInstance()方法前面加上synchronized 則執行效率會比較低,沒創建一次,都得判斷是否lock住。可以加上雙重判斷,來減少鎖的判斷次數。同步鎖是該類所屬的字節碼文件對象。

class Single {
    private Single() {
    }
    private static Single s = null;
    public static Single getInstance() {
        if (s == null) {
            synchronized (Single.class) {
                if (s == null) {
                    s = new Single();
                }
            }
        }
        return s;
    }
}

二、進程同步問題
問題描述:設有兩個線程,一個線程負責寫數據(前後兩次數據不同,可以設置flag變量來進行input的切換),另一個線程負責讀數據。問如何實現同步。


public class InputOutput {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        Resource r = new Resource();
        Input in = new Input(r);
        Output out = new Output(r);
        Thread thread = new Thread(in);
        Thread thread1 = new Thread(out);
        thread.start();
        thread1.start();

    }

}
class Resource{
    String name ;
    String sex ;
} 
class Input implements Runnable{
    Resource s;
    Input(Resource s){
        this.s= s;
    } 
    public void run(){
        boolean flag = true;
        while(true){
            synchronized(s){
            if(flag){
                s.name = "張三";
                s.sex  =  "男";
                flag = false;
            }else{
                s.name = "麗麗";
                s.sex = "女";
                flag = true;
            }}
        }
    }
}
class Output implements Runnable{
    Resource s;
    Output(Resource s){
        this.s = s;
    }
    public void run(){
        while(true){
            synchronized(s){
        System.out.println(s.name+" "+s.sex);}      
    }}

}

代碼優化後:

public class InputOutput {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        Resource r = new Resource();
        Input in = new Input(r);
        Output out = new Output(r);
        Thread thread = new Thread(in);
        Thread thread1 = new Thread(out);
        thread.start();
        thread1.start();
    }
}

class Resource {
    private String name;
    private String sex;
    private boolean flag;

    public synchronized void set(String name, String sex) {
        if (!flag) {
            this.name = name;
            this.sex = sex;
            flag = true;
            this.notify();
        }
        try {
            this.wait();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public synchronized void info() {
        if (flag) {
            System.out.println(name + "..." + sex);
            flag = false;
            this.notify();
        }
        try {
            this.wait();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

class Input implements Runnable {
    Resource s;

    Input(Resource s) {
        this.s = s;
    }
    public void run() {
        boolean flag = true;
        while (true) {
            if (flag) {
                s.set("張三", "男");
                flag = false;
            } else {
                s.set("麗麗", "女");
                flag = true;
            }

        }
    }
}

class Output implements Runnable {
    Resource s;

    Output(Resource s) {
        this.s = s;
    }

    public void run() {
        while (true) {
            s.info();
        }
    }

}
發佈了41 篇原創文章 · 獲贊 2 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章