多線程安全問題
1.1解決線程安全問題的基本思想
(1)原因:當程式的多條語句在操作線程共享資料時(如買票例子中的票就是共享資源),
由于線程的随機性導緻,一個線程對多條語句,執行了一部分還沒執行完,另一個線程搶奪
到cpu 執行權參與進來執行,此時就導緻共享資料發生錯誤。比如買票例子中列印重票和
錯票的情況。
(2)解決方法:對多條操作共享資料的語句進行同步
首先想為什麼出現問題?(也是我們判斷是否有問題的标準)
是否是多線程環境
是否有共享資料
是否有多條語句操作共享資料
如何解決多線程安全問題呢?
基本思想:讓程式沒有安全問題的環境。
怎麼實作呢?
把多個語句操作共享資料的代碼給鎖起來,讓任意時刻隻能有一個線程執行即可。
.2Java 中多線程同步是什麼?
同步是用來解決多線程的安全問題的,在多線程中,同步能控制對共享資料的通路。
如果沒有同步,當一個線程在修改一個共享資料時,而另外一個線程正在使用或者更新同一
個共享資料,這樣容易導緻程式出現錯誤的結果。
1.3什麼是鎖?鎖的作用是什麼?
鎖就是對象, 鎖的作用是保證線程同步,解決線程安全問題。
持有鎖的線程可以在同步中執行,沒有鎖的線程即使獲得cpu 執行權,也進不去。
1.4同步的前提
(1)必須保證有兩個以上線程
(2)必須是多個線程使用同一個鎖,即多條語句在操作線程共享資料
(3)必須保證同步中隻有一個線程在運作
1.5. 同步的好處和弊端
好處:同步解決了多線程的安全問題
弊端:多線程都需要判斷鎖,比較消耗資源
1.6解決線程安全問題實作1
(1)同步代碼塊:
可以指定需要擷取哪個對象的同步鎖,使用synchronized 的代碼塊同樣需要鎖,但
他的鎖可以是任意對象,考慮到安全問題,一般還是使用同一個對象,相對來說效率較高。
注意:
雖然同步代碼快的鎖可以使任何對象,但是在進行多線程通信使用同步代碼快時,
必須保證同步代碼快的鎖的對象和,否則會報錯。
同步方法的鎖是this,也要保證同步方法的鎖的對象和調用wait、notify 和
notifyAll 的對象是同一個對象,也就是都是this 鎖代表的對象。
格式:
synchronized(對象){需要同步的代碼;}
同步可以解決安全問題的根本原因就在那個對象上。該對象如同鎖的功能。
同步代碼塊的對象可以是哪些呢?
下面就電影院買票問題進行說明:
package java.thread;
/**
* 線程同步
*/
public class ThreadDemo4 {
public static void main(String[] args) {
Saler s1 = new Saler("s1",1);
Saler s2 = new Saler("s2",1);
s1.start();
s2.start();
}
}
/**
* 售票員
*/
class Saler extends Thread {
//總票數
private static int tickets = 100 ;
private String name0;
private int sleep;
public Saler(String name0, int sleep) {
this.name0 = name0;
this.sleep = sleep;
}
public String getName0() {
return name0;
}
public void setName0(String name0) {
this.name0 = name0;
}
public void run() {
try {
while(true){
int temp = 0 ;
synchronized (Saler.class){
temp = tickets ;
Thread.sleep(50);
tickets -- ;
}
if(temp <= 0 ){
return ;
}
else{
System.out.println(name0 +" : " + temp);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}