天天看點

線程安全與synchronized關鍵字

本文主要内容:

(1)線程安全問題

(2)synchronized關鍵字

(3)join方法

(4)sleep方法與wait方法的差別

1.解決線程安全問題

讓倉庫對象被線程通路的時候,倉庫對象被鎖定,倉庫對象隻能被一個線程通路,其他線程處于等待狀态。

public class House {
    private ArrayList<String> list = new ArrayList<>();
    //向集合中添加元素的方法
    public synchronized void add(){
        if(list.size()<20){
            list.add("a");
        }else {
            try {
                this.notifyAll();
                this.wait();//倉庫調用wait(),不是倉庫對象等待,而是調用倉庫生産者線程進入等待狀态
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    //從集合中取元素
    public synchronized void get(){
        if(list.size()>0){
            list.remove(0);
        }else {
            try {
                this.notifyAll();
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
//Producer、Customer、TestMain類和上述一樣
//運作不會産生異常,線程安全
           

2.特征修飾符:synchronized

同步的,一個時間點隻有一個線程通路

(2-1)将synchronized關鍵字放在方法的結構上

public synchronized void get(){
    //鎖定的是調用方法時的那個對象
}
           

(2-2)将synchronized關鍵字放在方法(構造方法、塊)的内部

public void get(){
    synchronized(對象){
        ......
    }
}
           

3.通過上述的生産消費者模型總結

(1)利用線程安全鎖,特征修飾符synchronized,兩種不同的寫法,鎖定的是對象

(2)利用方法控制線程狀态來回切換方法如下:

wait(),notify(),notifyAll(),這些方法都是Object類中的方法

(3)Thread類中的方法

sleep(),setPriority();getPriority(),設定或擷取線程的優先級,數字越高優先級越高,更加容易擷取CPU配置設定的資源碎片

4.筆試題

(1)線程的幾種狀态

線程安全與synchronized關鍵字

(2)sleep與wait方法的差別

sleep():它是Thread類中的靜态方法,可以直接用類調用,需要用對象調用方法,喚醒不需要别人,不會釋放鎖

wait():他是Object類的方法,需要用對象來調用方法,通路對象的其他線程等待,需要其他對象調用notify喚醒,等待後會釋放鎖

5.比較重要的方法(Thead類中的join方法)

(1)設計一個模型,有兩個線程,将two線程加入one裡面

(2)設計模型時,two線程在one的run裡面建立,保證兩個有先後順序

(3)two.join

public class ThreadOne extends Thread{
    public void run(){
        System.out.println("thread one start");
        ThreadTwo two = new ThreadTwo();
        two.start();
        try {
            two.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("thread one end");
    }
}
public class ThreadTwo extends Thread {
    public void run(){
        System.out.println("thread two start");
        System.out.println("thraed two end");
    }
}
public class Test {
    public static void main(String[] args) {
        ThreadOne one = new ThreadOne();
        one.start();
    }
}
//運作結果
thread one start
thread two start
thraed two end
thread one end
           

(4)在寫一個如下模型,在建立一個ThreadThree,one開始啟動(啟動後睡眠5000s),two考試啟動(加入到one中2000s),three開始啟動(啟動後睡眠10000s),two開始加入到one中,2000s後one想将two從自己的線程中删除,但是two對象又被three對象鎖定了(10000s),所有one隻能等待three将two對象釋放後,才能踢掉。

public class ThreadOne extends Thread{
    public void run(){
        System.out.println("thread one start");
        ThreadTwo two = new ThreadTwo();
        two.start();
        try {
            two.join(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("thread one end");
    }
}
public class ThreadTwo extends Thread {
    public void run(){
        System.out.println("thread two start");
        ThreadThree three = new ThreadThree(this);
        three.start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("thread two end");
    }
}
public class ThreadThree extends Thread{
    private ThreadTwo two;
    public ThreadThree(ThreadTwo two){
        this.two = two;
    }
    public void run(){
        System.out.println("thread three start");
        synchronized (two){
            System.out.println("two is locked");
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("two is free");
        }
        System.out.println("thread three end");
    }
}
public class Test {
    public static void main(String[] args) {
        ThreadOne one = new ThreadOne();
        ThreadTwo two = new ThreadTwo();
        ThreadThree three = new ThreadThree(two);
        one.start();
    }
}
//運作結果
thread one start
thread two start
thread three start
two is locked
thread two end
two is free
thread three end
thread one end
           

繼續閱讀