執行緒安全問題出現的原因和解決方法
阿新 • • 發佈:2019-01-03
執行緒安全問題:
執行緒安全出現的根本原因:
1.存在兩個或者兩個以上的執行緒物件共享同一個資源;
2.多執行緒操作共享資原始碼有多個語句。
執行緒安全問題的解決方案(2個):
方式一:同步程式碼塊
格式:synchronize(鎖物件){
需要被同步的程式碼
}
同步程式碼塊需要注意的事項:
1.鎖物件可以是任意的一個物件;
2.一個執行緒在同步程式碼塊中sleep了,並不會釋放鎖物件;
3.如果不存線上程安全問題,千萬不要使用同步程式碼塊;
4.鎖物件必須是多執行緒共享的一個資源,否則鎖不住。
例子:三個視窗售票
class SaleTicket extends Thread{
static int num = 50;//票數 非靜態的成員變數,非靜態的成員變數資料是在每個物件中都會維護一份資料的。
public SaleTicket(String name) {
super(name);
}
@Override
public void run() {
while(true){
//同步程式碼塊
synchronized ("鎖") {
if(num>0){
System.out.println(Thread.currentThread().getName()+"售出了第"+num+"號票");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
num--;
}else{
System.out.println("售罄了..");
break;
}
}
}
}
}
public class Demo4 {
public static void main(String[] args) {
//建立三個執行緒物件,模擬三個視窗
SaleTicket thread1 = new SaleTicket("視窗1");
SaleTicket thread2 = new SaleTicket("視窗2");
SaleTicket thread3 = new SaleTicket("視窗3");
//開啟執行緒售票
thread1.start();
thread2.start();
thread3.start();
}
}
方式二:同步函式(同步函式就是使用synchronized修飾一個函式)
同步函式注意事項:
1.如果函式是一個非靜態的同步函式,那麼鎖物件是this物件;
2.如果函式是靜態的同步函式,那麼鎖物件是當前函式所屬的類的位元組碼檔案(class物件);
3.同步函式的鎖物件是固定的,不能由自己指定。
例子:兩夫妻取錢
class BankThread extends Thread{
static int count = 5000;
public BankThread(String name){
super(name);
}
@Override //
public synchronized void run() {
while(true){
synchronized ("鎖") {
if(count>0){
System.out.println(Thread.currentThread().getName()+"取走了1000塊,還剩餘"+(count-1000)+"元");
count= count - 1000;
}else{
System.out.println("取光了...");
break;
}
}
}
}
public class Demo1 {
public static void main(String[] args) {
//建立兩個執行緒物件
BankThread thread1 = new BankThread("老公");
BankThread thread2 = new BankThread("老婆");
//呼叫start方法開啟執行緒取錢
thread1.start();
thread2.start();
}
}
推薦使用:同步程式碼塊
原因:
1.同步程式碼塊的鎖物件可以由我們自由指定,方便控制;
2.同步程式碼塊可以方便的控制需要被同步程式碼的範圍,同步函式必須同步函式的所有程式碼。