解決線程安全的幾種方式


一、解決線程安全總體可分為兩大類:

1.使用synchronized關鍵字(可修飾代碼塊或方法)

(1)使用synchronized關鍵字修飾代碼塊

public class ThreadDemo {
	public static void main(String[] args) {
		ThreadSafe1 thread = new ThreadSafe1();
		Thread t1 = new Thread(thread);
		Thread t2 = new Thread(thread);
		Thread t3 = new Thread(thread);
		t1.setName("窗口一");
		t2.setName("窗口二");
		t3.setName("窗口三");
		t1.start();
		t2.start();
		t3.start();
	}
}

class ThreadSafe1 implements Runnable{
	
	//定義車票的數量
	private int ticket = 100;
	
	@Override
	public void run() {		
		while(true) {
			synchronized(ThreadSafe1.class) {   //同步監視器為ThreadSafe1.class,它只加載一次,是唯一的,該同步代碼塊里包含着共享數據的操作
				if(ticket > 0) {
					System.out.println(Thread.currentThread().getName()+":"+"出售第"+ticket+"張車票");
					//車票數量減一
					ticket--;
				}else {
					break;
				}
			}
		}	
	}	
}

(2)使用synchronized關鍵字修飾方法

public class ThreadDemo {
	public static void main(String[] args) {
		ThreadSafe2 thread = new ThreadSafe2();
		Thread t1 = new Thread(thread);
		Thread t2 = new Thread(thread);
		Thread t3 = new Thread(thread);
		t1.setName("窗口一");
		t2.setName("窗口二");
		t3.setName("窗口三");
		t1.start();
		t2.start();
		t3.start();
	}
}
class ThreadSafe2 implements Runnable{
	
	//定義車票的數量
	private int ticket = 100;
	
	@Override
	public void run() {		
		while(true) {
			//調用窗口售票方法
			sale();
			if(ticket == 0) {
				break;
			}
	    }	
	}	
	//實現窗口售票
	public synchronized void sale() {   //該方法的同步監視器為ThreadSafe2的對象,它是唯一的,這里面也存放着對共享數據的操作
		if(ticket > 0) {
			System.out.println(Thread.currentThread().getName()+":"+"出售第"+ticket+"張車票");
			//車票數量減一
			ticket--;
		}
	}
}

2.使用Lock鎖方式解決線程安全問題

public class ThreadDemo {
	public static void main(String[] args) {
		ThreadSafe3 thread = new ThreadSafe3();
		Thread t1 = new Thread(thread);
		Thread t2 = new Thread(thread);
		Thread t3 = new Thread(thread);
		t1.setName("窗口一");
		t2.setName("窗口二");
		t3.setName("窗口三");
		t1.start();
		t2.start();
		t3.start();
	}
}
class ThreadSafe3 implements Runnable{
	
	//定義車票的數量
    private int ticket = 100;
    private ReentrantLock lock = new ReentrantLock();

	@Override
	public void run() {
		while(true) {
			try {
				lock.lock();  //對對操作共享數據的代碼進行加鎖
				//進行線程休眠,增加其他線程調用的機會
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				if(ticket > 0) {
					System.out.println(Thread.currentThread().getName()+":"+"出售第"+ticket+"張車票");
					//車票數量減一
					ticket--;
				}else {
					break;
				}
			}finally {
				lock.unlock(); //進行解鎖
			}
		}		
	}		
}

二、synchronized關鍵字與Lock鎖方式的區別

(1)兩者都可以解決線程安全問題

(2)synchronized關鍵字既可以修飾代碼塊又可以修飾方法;而Lock鎖方式只可以修飾代碼塊

(3)synchronied關鍵字修飾的代碼塊或方法在運行結束后,會自動釋放鎖;而Lock鎖方式需手動為代碼塊加鎖並釋放鎖

(4)從性能上,Lock鎖方式優於synchronized關鍵字


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM