一、線程鎖
線程安全問題
其實,線程安全問題都是由全局變量及靜態變量引起的。若每個線程中對全局變量、靜態變量只有讀操作,而無寫操作,一般來說,這個全局變量是線程安全的;若有多個線程同時執行寫操作,一般都需要考慮線程同步,否則的話就可能影響線程安全。
由于線程休眠的特性,從哪休眠就從哪繼續執行(一個線程的事情還沒干完就被其他線程擠下去了),回來繼續干就會導致操作的全局變量或靜態變量出現問題。
為了解決這個問題,我們就需要讓線程執行完畢(不能被其他線程擠下去),以下是幾種解決辦法。
1、同步代碼塊
保證代碼塊執行完畢,再切換線程。
公式:
synchronized(任意對象){
線程要操作的共享數據
}
調用類
1 2 3 4 5 6 7 8 9 10 11 12 |
?
|
同步代碼塊
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
?
|
同步代碼塊中的鎖對象可以是任意的對象;但多個線程時,要使用同一個鎖對象才能夠保證線程安全。
2、同步方法
還可以將需要同步的代碼塊,抽出來一個方法,使用synchronized字段修飾。
public?synchronized?void method(){
可能會產生線程安全問題的代碼
}
同步方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
?
?
|
同步方法中的鎖對象是this,如果是靜態同步方法的話同步鎖是本類類名.class
3、Lock接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
?
?
?
|
二、死鎖
同步鎖使用的弊端:當線程任務中出現了多個同步(多個鎖)時,如果同步中嵌套了其他的同步。這時容易引發一種現象:程序出現無限等待,這種現象我們稱為死鎖。這種情況能避免就避免掉。
三、等待喚醒機制
線程之間的通信:
多個線程在處理同一個資源,但是處理的動作(線程的任務)卻不相同。通過一定的手段使各個線程能有效的利用資源。而這種手段即——等待喚醒機制。
等待喚醒機制
等待喚醒機制所涉及到的方法:
其實,所謂喚醒的意思就是讓線程池中的線程具備執行資格。必須注意的是,這些方法都是在同步中才有效。同時這些方法在使用時必須標明所屬鎖,這樣才可以明確出這些方法操作的到底是哪個鎖上的線程。
仔細查看JavaAPI之后,發現這些方法并不定義在Thread中,也沒定義在Runnable接口中,卻被定義在了Object類中,為什么這些操作線程的方法定義在Object類中?
因為這些方法在使用時,必須要標明所屬的鎖,而鎖又可以是任意對象。能被任意對象調用的方法一定定義在Object類中。
1 package cn.x5456.demo;2 3 public class ThreadDemo {4 public static void main(String[] args) {5 Resource r = new Resource();6 7 // 共享數據8 Input in = new Input(r);9 Output out = new Output(r); 10 11 Thread tin = new Thread(in); 12 Thread tout = new Thread(out); 13 14 tin.start(); 15 tout.start(); 16 } 17 }
1 package cn.x5456.demo;2 3 public class Input implements Runnable{4 private Resource r;5 int i = 0;6 7 public Input(Resource r){8 this.r=r;9 } 10 11 12 public void run() { 13 while (true){ 14 synchronized (r){ //要使用同一個對象來看著Input和Output兩個同步方法(否則就各自走各自的了) 15 if(r.flag){ 16 try { 17 r.wait(); //使用同一個對象才能等待+啟動 18 } catch (InterruptedException e) { 19 e.printStackTrace(); 20 } 21 } 22 if(i%2==0){ 23 r.name = "張三"; 24 r.sex = "男"; 25 }else{ 26 r.name = "lisi"; 27 r.sex = "nv"; 28 } 29 i++; 30 r.flag = true; 31 r.notify(); //喚醒另一邊 32 } 33 } 34 } 35 }
1 package cn.x5456.demo;2 3 public class Output implements Runnable{4 private Resource r;5 6 public Output(Resource r) {7 this.r = r;8 }9 10 11 @Override 12 public void run() { 13 while (true){ 14 synchronized (r){ 15 if(!r.flag){ 16 try { 17 r.wait(); 18 } catch (InterruptedException e) { 19 e.printStackTrace(); 20 } 21 } 22 System.out.println(r.name+".."+r.sex); 23 //標記改成false,喚醒對方線程 24 r.flag = false; 25 r.notify(); 26 } 27 } 28 } 29 }
1 package cn.x5456.demo; 2 3 public class Resource { 4 String name; 5 String sex; 6 boolean flag = false; 7 }
?