1. 程式人生 > >執行緒安全問題出現的原因和解決方法

執行緒安全問題出現的原因和解決方法

執行緒安全問題:

執行緒安全出現的根本原因:

    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.同步程式碼塊可以方便的控制需要被同步程式碼的範圍,同步函式必須同步函式的所有程式碼。