1. 程式人生 > >13、synchronized同步程式碼塊

13、synchronized同步程式碼塊

synchronized同步方法的弊端

當A執行緒呼叫物件中的同步方法時執行任務的時間很長,這樣B執行緒要一直晾著,啥事也幹不了。這就是弊端!

假設A,B,C,D等多位顧客正在超市收銀臺結賬,A正在結賬的時候發現自己錢沒帶,需要回家去拿,剩下的顧客如果一直等著A回家拿完錢結完賬才能買單,那就很耽誤後面顧客的時間。這時候應該讓後面的人結賬走人。

放到執行緒中就是 A執行緒任務花費時間長,應該讓其他執行緒先執行。

package com.demo15;

import java.text.SimpleDateFormat;

public class MyObject {
    synchronized public void myTaskA(){
        try {
            System.out.println("myTaskA");
            System.out.println("myTaskA即將進入睡眠,時間=" +
                    SimpleDateFormat.getDateTimeInstance().format(System.currentTimeMillis()));
            Thread.sleep(5000);
            System.out.println("myTaskA即將結束睡眠,時間=" +
                    SimpleDateFormat.getDateTimeInstance().format(System.currentTimeMillis()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    synchronized public void myTaskB(){
        System.out.println("myTaskB");
    }
}
package com.demo15;

public class ThreadA extends Thread {
    MyObject myObject = new MyObject();

    public ThreadA(MyObject myObject) {
        this.myObject = myObject;
    }

    @Override
    public void run() {
        myObject.myTaskA();
    }
}
package com.demo15;

public class ThreadB extends Thread {
    MyObject myObject = new MyObject();

    public ThreadB(MyObject myObject) {
        this.myObject = myObject;
    }

    @Override
    public void run() {
        myObject.myTaskB();
    }
}
package com.demo15;

import java.text.SimpleDateFormat;

public class Run {
    public static String begintime ;
    public static void main(String[] args) {
        MyObject myObject = new MyObject();
        ThreadA threadA = new ThreadA(myObject);
        ThreadB threadB = new ThreadB(myObject);
        threadA.start();
        threadB.start();
    }
}

執行結果:

myTaskA
myTaskA即將進入睡眠,時間=2018-12-11 23:06:21
myTaskA即將結束睡眠,時間=2018-12-11 23:06:26
myTaskB

通過結果可知,A執行同步方法花費了5秒,這期間B什麼也不能做!

作出以下的修改:

package com.demo15;

import java.text.SimpleDateFormat;

public class MyObject {
    public void myTaskA(){
        try {
            synchronized(this){
                System.out.println("myTaskA");
            }
            System.out.println("myTaskA即將進入睡眠,時間=" +
                    SimpleDateFormat.getDateTimeInstance().format(System.currentTimeMillis()));
            Thread.sleep(5000);
            System.out.println("myTaskA即將結束睡眠,時間=" +
                    SimpleDateFormat.getDateTimeInstance().format(System.currentTimeMillis()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    synchronized public void myTaskB(){
        System.out.println("myTaskB");
    }
}

此時的執行結果為:

myTaskA
myTaskB
myTaskA即將進入睡眠,時間=2018-12-11 23:20:05
myTaskA即將結束睡眠,時間=2018-12-11 23:20:10

當A執行完同步程式碼塊之後,立即釋放鎖,讓其他執行緒執行!然後再獲取CPU資源來執行後續的花費事件長的任務。

通過上面的例子我們可以看到 使用同步程式碼塊 相對使用同步方法的優勢!