-
- 多個線程在操作共享的數據。
- 操作共享數據的線程代碼有多條。
- 當一個線程在執行操作共享數據的多條代碼過程中,其他線程參與了運算。 就會導致線程安全問題的產生。
- 釋放資格的同時,釋放執行權
- 使當前正在執行的線程以指定的毫秒數暫停。
- millis: 以毫秒為單位的睡眠時間長度。
- InterruptedException: 如果任何線程中斷當前線程,拋出此異常時,當前線程的中斷狀態將被清除。
- 思路: 將多條操作共享數據的線程代碼封裝起來,當有線程在執行這些代碼的時候,其他線程不可以參與運算。 必須要當前線程把這些代碼都執行完畢後,其他線程才可以參與運算。
- 在 Java 中,用同步代碼塊就可以解決這個問題。
- 同步好處: 解決了線程安全問題。
- 同步弊端: 相對降低了效率,因為同步外的線程都會判斷同步鎖。
- 同步前提: 同步中必須有多個線程並使用同一個鎖。
- 簡單來講,相當於一道鎖(同步鎖),當一個線程進入同步代碼塊後,鎖住讓其他線程進不來。
- 格式: synchronized(對象) { //需要被同步的代碼 }
- 使用的鎖是 this (當前對象)
- 同步函數和同步代碼塊的區別: 同步函數的鎖是固定的 this。 同步代碼塊的鎖是任意的對象。
- 注意: 建議使用同步代碼塊,同步函數是簡寫。
- 靜態的同步函數使用的鎖是該函數所屬字節碼文件對象, 可以用 getClass 方法獲取,也可以用當前 類名.class 表示。
public class Ticket extends Thread {
private int num = 10;
Object obj = new Object();//創建對象傳入同步代碼塊
public void run() {
while(true) {
synchronized(obj) {//簡單來講,相當於一道鎖(同步鎖),讓其他線程進不來
if(num > 0) {//票數不能為負數
try {
Thread.sleep(10);//暫停十毫秒
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName() + " sale " + num--);
}
}
}
}
}
public class TicketDemo {
public static void main(String[] args) {
Ticket t = new Ticket();//創建一個線程任務對象
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
Thread t3 = new Thread(t);
Thread t4 = new Thread(t);
t1.start();
t2.start();
t3.start();
t3.start();
}
}
打印結果
Thread-1 sale 10
Thread-1 sale 9
Thread-1 sale 8
Thread-1 sale 7
Thread-1 sale 6
Thread-2 sale 5
Thread-2 sale 4
Thread-2 sale 3
Thread-2 sale 2
Thread-2 sale 1