前言:關(guān)于synchronized、wait、notify已經(jīng)notifyAll大家應(yīng)該不陌生,現(xiàn)在我大致說一下我的理解。

一:synchronized

synchronized中文解釋是同步,那么什么是同步呢,解釋就是程序中用于控制不同線程間操作發(fā)生相對順序的機制,通俗來講就是2點,第一要有多線程,第二當多個線程同時競爭某個資源的時候會有先后順序。在java中有三種寫synchronized的方式

  • 第一種:

    • 寫在普通方面的前面,這種表示對實例對象加鎖。

  • 第二種:

    • 寫在靜態(tài)方法前面,這種表示對類對象加鎖

  • 第三種:

    • 寫在代碼塊中,鎖是Synchonized括號里配置的對象(可能是實例對象,也可能是類對象)

總體說來就2種,一種就是鎖實例對象,一種鎖類對象。

鎖實例對象就是當多個線程同時操作這個實例對象的時候必須先獲取鎖,如果無法獲取鎖,則必須處于等待狀態(tài),而和鎖類對象區(qū)別是,當多個線程同時操作的時候,任何以這個類對象實例化的對象都要獲取鎖才能操作。舉個簡單例子

比如一個群人去打飯,只要是人就必須排隊等待,一個個的打飯。不管是誰,但是吃完飯之后把盤子送回原地,但是這個時候不同的人可能吃飯快慢不同,但是肯定先吃飯后送盤子?,F(xiàn)在寫段代碼我們比對一下。

Android培訓,安卓培訓,手機開發(fā)培訓,移動開發(fā)培訓,云培訓培訓

public class RunnableTest implements Runnable {    private synchronized  void testSyncMethod() {        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getId() + "testSyncMethod:" + i);
        }
    }    public void run() {
     testSyncMethod();
    }    public static void main(String[] args) {
        ExecutorService exec = Executors.newFixedThreadPool(2);
        RunnableTest rt = new RunnableTest();
        RunnableTest rt1 = new RunnableTest();
        exec.execute(rt);
        exec.execute(rt1);
        exec.shutdown();
    }

Android培訓,安卓培訓,手機開發(fā)培訓,移動開發(fā)培訓,云培訓培訓

按照我們的理論輸出結(jié)果肯定是無序排列的。如圖Android培訓,安卓培訓,手機開發(fā)培訓,移動開發(fā)培訓,云培訓培訓

Android培訓,安卓培訓,手機開發(fā)培訓,移動開發(fā)培訓,云培訓培訓

public class RunnableTest implements Runnable {    private void testSyncBlock() {        synchronized (RunnableTest.class) {            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getId()+"testSyncBlock:" + i);
            }
        }
    }    public void run() {
     testSyncBlock();
    }    public static void main(String[] args) {
        ExecutorService exec = Executors.newFixedThreadPool(2);
        RunnableTest rt = new RunnableTest();
        RunnableTest rt1 = new RunnableTest();
        exec.execute(rt);
        exec.execute(rt1);
        exec.shutdown();
    }
}

Android培訓,安卓培訓,手機開發(fā)培訓,移動開發(fā)培訓,云培訓培訓

而這段代碼輸入結(jié)果肯定是有序的。如下Android培訓,安卓培訓,手機開發(fā)培訓,移動開發(fā)培訓,云培訓培訓

那么我們在思考一個問題,如果類A有2個方法,如果我們在其中一個方法前面加入了synchronized,哪意味著我們別的線程調(diào)用這個類的另一個方法也需要獲取鎖才可以執(zhí)行,也是另一個方法只是讀,這樣一來性能就大大的降低,所以我們在實際開發(fā)中盡量少在方法前加入synchronized,那么我們應(yīng)該怎么做呢,既然是實際對象我們只需要加入一個類,鎖定此類,只需要讓類的一個方法進行鎖定即可。ok下面代碼如下

Android培訓,安卓培訓,手機開發(fā)培訓,移動開發(fā)培訓,云培訓培訓

public class A {    private Object obj="123";    public  void a(){        synchronized (obj) {            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread() + "a:" + i);
            }
        }
    }    public void b(){            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread() + "b:" + i);
            }

    }
}public class B implements Runnable{    private A a;    public B(A a){        this.a=a;
    }    public void run() {
        a.b();
    }
}public class C implements Runnable {    private A a;    public C(A a){        this.a=a;
    }    public void run() {
        a.a();
    }
}public class E implements Runnable{    private A a;    public E(A a){        this.a=a;
    }    public void run() {
        a.a();
    }
}public class D {    public static void main(String[] args) {
        A a=new A();
        ExecutorService executorService= Executors.newCachedThreadPool();
        executorService.execute(new E((a)));
        executorService.execute(new B(a));
        executorService.execute(new C(a));
        executorService.shutdown();
    }
}

Android培訓,安卓培訓,手機開發(fā)培訓,移動開發(fā)培訓,云培訓培訓

按照我們理論這段代碼執(zhí)行順序是第一個線程和第二個線程無序,第三個線程必須等待第一個線程執(zhí)行完畢才可以,測試結(jié)果也論證了我們的理論如下

Android培訓,安卓培訓,手機開發(fā)培訓,移動開發(fā)培訓,云培訓培訓

二:wait、notify已經(jīng)notifyAll

wait、notify、notifyAll是Object對象的屬性,并不屬于線程。我們先解釋這三個的一個很重要的概念

wait:使持有該對象的線程把該對象的控制權(quán)交出去,然后處于等待狀態(tài)(這句話很重要,也就是說當調(diào)用wait的時候會釋放鎖并處于等待的狀態(tài))

notify:通知某個正在等待這個對象的控制權(quán)的線程可以繼續(xù)運行(這個就是獲取鎖,使自己的程序開始執(zhí)行,最后通過notify同樣去釋放鎖,并喚醒正在等待的線程)

notifyAll:會通知所有等待這個對象控制權(quán)的線程繼續(xù)運行(和上面一樣,只不過是喚醒所有等待的線程繼續(xù)執(zhí)行)

這個就好了,從上面的解釋我們可以看出通過wait和notify可以做線程之間的通信,當A線程處理完畢通知B線程執(zhí)行,B線程執(zhí)行完畢以后A線程可以繼續(xù)執(zhí)行。ok我們使用例子來說明。

 

Android培訓,安卓培訓,手機開發(fā)培訓,移動開發(fā)培訓,云培訓培訓

public class Temp {    int count=0;    public void waiter() throws InterruptedException {        synchronized (this) {
               System.out.println("等待");
               wait();
               System.out.println(this.count);
        }
    }    public void notifyer() throws InterruptedException {        synchronized (this){
            TimeUnit.SECONDS.sleep(1);
            System.out.println("喚醒");            for (int i=0;i<10;i++){
                System.out.println(Thread.currentThread()+"notifyer:"+i);
                count+=i;
            }
            notify();
        }
    }public class Waiter implements Runnable{    private Temp temp;    public Waiter(Temp temp){        this.temp=temp;
    }    public void run() {        try {
            temp.waiter();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}public class Notifyer implements Runnable{    private Temp temp;    public Notifyer(Temp temp){        this.temp=temp;
    }    public void run() {        try {
            temp.notifyer();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}   public static void main(String[] args) {
        Temp temp=new Temp();
        ExecutorService executorService= Executors.newCachedThreadPool();
        executorService.execute(new Waiter(temp));
        executorService.execute(new Notifyer(temp));
        executorService.shutdown();
    }

Android培訓,安卓培訓,手機開發(fā)培訓,移動開發(fā)培訓,云培訓培訓

其中在notify中加入休眠1s目的是讓線程waiter先執(zhí)行更能看明白

Android培訓,安卓培訓,手機開發(fā)培訓,移動開發(fā)培訓,云培訓培訓

在說一下wait和sleep的區(qū)別

區(qū)別1:在wait期間對象鎖使釋放的

區(qū)別2:可以通過notify和notifyAll,或者玲命令到期,從wait中恢復執(zhí)行。如果wait不接受任何參數(shù),這種wait將無線的等待下去,直到線程收到notify或notifyall的消息