先來看一段程式碼:
class MyThread implements Runnable{ private int count = 10; @Override public void run() { while(count > 0) { System.out.println(Thread.currentThread().getName() + "开始执行"); System.out.println("count还剩" + --count); System.out.println(Thread.currentThread().getName() + "执行结束"); System.out.println(); } } } public class Test{ public static void main(String[] args) { MyThread myThread = new MyThread(); new Thread(myThread).start(); new Thread(myThread).start(); new Thread(myThread).start(); } }
運行結果如下:
Thread-0开始执行 Thread-2开始执行 Thread-1开始执行 count还剩8 count还剩9 Thread-2执行结束 count还剩7 Thread-1执行结束 Thread-1开始执行 Thread-0执行结束 Thread-0开始执行 count还剩5 Thread-0执行结束 Thread-2开始执行 count还剩4 Thread-2执行结束 Thread-2开始执行 count还剩3 count还剩6 Thread-2执行结束 Thread-2开始执行 Thread-0开始执行 count还剩2 Thread-2执行结束 Thread-2开始执行 count还剩0 Thread-2执行结束 Thread-1执行结束 count还剩1 Thread-0执行结束
很顯然這不是我們想要的結果,我們想要的結果是:一個獨自完整地按順序跑完自己的run()方法,然而上面的結果是亂序的:上一個線程還沒跑完自己的任務,第二個線程就進來了。那麼如何來解決這個問題呢?
首先我們來分析一下,三個線程同時拿到我們自己創建的物件myThread,然後啟動這三個線程,這三個線程會同時進入這個run()方法進行執行。如果我們想要每個執行緒進入後完整的跑完自己的任務,這時候就需要把這個myThread物件鎖起來,不讓其他執行緒拿到,這樣就能實現。就比如說,有一個房間,你進去之後,不要其他人再進來,你就得把門鎖住一個道理。
在Java裡面為我們提供了一個叫做「synchronized」的鎖子。那麼它應該怎樣來使用呢?
「synchronized」的兩種模式:同步方法、同步程式碼區塊。
一、物件鎖定:
1、同步程式碼區塊:在程式碼區塊前方加上synchronized(要鎖定的物件)。
class MyThread implements Runnable{ private int count = 10; @Override public void run() { synchronized (this) { while(count > 0) { System.out.println(Thread.currentThread().getName() + "开始执行"); System.out.println("count还剩" + --count); System.out.println(Thread.currentThread().getName() + "执行结束"); System.out.println(); } } } } public class Test{ public static void main(String[] args) { MyThread myThread = new MyThread(); new Thread(myThread).start(); new Thread(myThread).start(); new Thread(myThread).start(); } }
2、同步方法:在方法的回傳值前面加上synchronized關鍵字。
class MyThread implements Runnable{ private int count = 10; @Override public void run() { while(count > 0) { count--; fun(); } } public synchronized void fun() { System.out.println(Thread.currentThread().getName() + "开始执行"); System.out.println("count还剩" + count); System.out.println(Thread.currentThread().getName() + "执行结束"); System.out.println(); } } public class Test{ public static void main(String[] args) { MyThread myThread = new MyThread(); new Thread(myThread).start(); new Thread(myThread).start(); new Thread(myThread).start(); } }
二、全域鎖定:
在上面,我們鎖住的都是myThread對象,如果要鎖住多個物件的同一個方法又該怎麼辦呢?
這裡與物件鎖定也有兩種方法:同步方法和同步程式碼區塊。
1、同步程式碼區塊前的括號裡寫成想要鎖住的方法的類別.class
class MyThread implements Runnable{ private static int count = 10; @Override public void run() { synchronized (MyThread.class) { while(count > 0) { count--; fun(); } } } public void fun() { System.out.println(Thread.currentThread().getName() + "开始执行"); System.out.println("count还剩" + count); System.out.println(Thread.currentThread().getName() + "执行结束"); System.out.println(); } } public class Test{ public static void main(String[] args) { MyThread myThread = new MyThread(); new Thread(myThread).start(); new Thread(myThread).start(); new Thread(myThread).start(); } }
2、在前面所說同步方法的基礎上,加上static關鍵字,就可以實作全域鎖。
class MyThread implements Runnable{ private static int count = 10; @Override public void run() { while(count > 0) { fun(); } } public synchronized static void fun() { System.out.println(Thread.currentThread().getName() + "开始执行"); System.out.println("count还剩" + count); System.out.println(Thread.currentThread().getName() + "执行结束"); System.out.println(); count--; } } public class Test{ public static void main(String[] args) { MyThread myThread = new MyThread(); new Thread(myThread).start(); new Thread(myThread).start(); new Thread(myThread).start(); } }
相關文章:
Java同步鎖定(synchronized)的範例程式碼分享
詳解Java中synchronized關鍵字的死鎖和記憶體佔用問題
相關影片:
以上是Java:詳細講解物件鎖定「synchronized」與全域鎖的詳細內容。更多資訊請關注PHP中文網其他相關文章!