多執行緒,你覺得你安全了?(執行緒安全問題)

遅咲きの向日葵發表於2020-12-24

多執行緒de小事情

導航不迷路:
  1. 程式、程式以及執行緒的愛恨情仇
  2. 最簡單實現多執行緒的方法(Thread)
  3. 簡單易懂的多執行緒(通過實現Runnable介面實現多執行緒)
  4. 常用獲取執行緒基本資訊的方法(新手專屬)


預備知識:

在探索多執行緒安全問題之前,我們需要了解一些相關知識;

執行緒的狀態

在這裡插入圖片描述

1.新生狀態;

用new關鍵字建立一個執行緒後,這個執行緒就是出於新生狀態;

2.就緒狀態;

執行緒的Start()方法被呼叫後,等待分配CPU時就是處於就緒狀態(也稱之為有資源無資格);

3.執行狀態;

執行緒的run()方法被執行,被CPU選中;(有資源,有資格)

4.阻塞狀態;

暫停某個執行緒的執行,等待某個條件的發生;

有四種原因導致阻塞狀態;

1.執行sleep()方法,使當前執行緒休眠,處於阻塞狀態;當指定時間到達後進入就緒狀態;

程式碼如下:

package com.bjsxt.threadMethod;

public class MyThreadSleep implements Runnable{

	@Override
	public void run() {
		try {
			System.out.println("my執行緒睡著了");
			Thread.sleep(1000);
			System.out.println("my執行緒醒了");
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

}

測試類程式碼:

package com.bjsxt.threadMethod;

public class TestSleep {
	public static void main(String[] args) throws InterruptedException {
		MyThreadSleep my = new MyThreadSleep();
		Thread t = new Thread(my);
		t.start();
		System.out.println("主執行緒睡著");
		Thread.sleep(2000);
		System.out.println("主執行緒醒了");
	}
}

執行效果:
在這裡插入圖片描述

2.執行wait()方法,使當前執行緒進入阻塞狀態,當呼叫notify()方法喚醒這個執行緒後,進入就緒狀態;

暫時不做演示:在後續生產者、消費者模式中進行演示;

3.Join()執行緒聯合:當某個執行緒需要等待另一個執行緒執行結束後,才能執行是使用join()方法;

程式碼如下:

public class MyThreadJoin1 implements Runnable{
	@Override
	public void run() {
		for(int i=0;i<10;i++) {
			System.out.println(Thread.currentThread().getName()+"----"+i);
		}
		
	}
}

測試類程式碼:

public class TestJoin1 {
	public static void main(String[] args) throws InterruptedException {
		MyThreadJoin my = new MyThreadJoin();
		Thread t = new Thread(my);
		t.start();
		for(int i=0;i<10;i++) {
			if(i==2) {
				t.join();
			}
			System.out.println("----------"+Thread.currentThread().getName()+"---"+i);
		}
		
	}
	
	
}

執行效果:
在這裡插入圖片描述

4.執行緒執行時,某個操作進入阻塞狀態,比如io流(read(),write()方法本身就是阻塞的 方法)只有當阻塞原因消失後,執行緒才會進入就緒狀態;

5.死亡狀態;

死亡狀態是執行緒的最後一個狀態;

導致死亡狀態有兩個原因;

1.執行緒正常執行結束;

2.強制終止執行緒;
當執行緒處於死亡狀態後,不能再回到其他狀態;

多執行緒在訪問共享資源時的確有優點,速度快;但是會出現安全性問題,資料錯亂;

案例:設計一個火車售票模擬程式;假如只剩五張票,三個視窗同時售票,每個視窗都有100人在排隊;

車票類程式碼:

public class Ticket implements Runnable{
	private int ticket=5;
	@Override
	public void run() {
		for(int i=0;i<100;i++) {
			if(ticket>0) {
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+"正在賣第"+ticket--+"張票");
		
			}
	
		}
	}	

}

測試類程式碼

public class TestTicket {
	public static void main(String[] args) {
		Ticket t = new Ticket();
		Thread thread1 = new Thread(t,"A視窗");
		Thread thread2 = new Thread(t,"B視窗");
		Thread thread3 = new Thread(t,"B視窗");
		thread1.start();
		thread2.start();
		thread3.start();
	}

}

效果圖:
如圖所示由於多執行緒的安全問題導致資料錯亂的問題;
在這裡插入圖片描述


つづく…

感謝您的觀看;後續仍然會不斷更新多執行緒,最終會以生產者消費者模式的小專案結束;
敬請期待;

相關文章