1. 程式人生 > >用於解決多執行緒安全問題的三種方式

用於解決多執行緒安全問題的三種方式

用於解決多執行緒安全問題的方式:
1. 同步程式碼塊 (隱式鎖)
2. 同步方法(隱式鎖)
3. 同步鎖 Lock( jdk 1.5 後)
 注意:是一個顯示鎖,需要通過 lock() 方法上鎖,必須通過 unlock() 方法進行釋放鎖

下面舉一個售票例子:

1)同步程式碼塊

package com.lxj.juc;

public class TestSync {

	public static void main(String[] args) {
		Ticket ticket = new Ticket();
		new Thread(ticket).start();
		new Thread(ticket).start();
		new Thread(ticket).start();
	}
	
}
class Ticket implements Runnable{

	private int ticket = 100;
	
	@Override
	public void run() {
		while(true) {
			synchronized(this) {  //this代表對當前物件上鎖
				if(ticket > 0) {
					try {
						Thread.sleep(200);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()+" : 購票成功,餘票為:" +  --ticket );
				}else {
					break;
				}
			}
		}
	}
	
}
執行結果:
Thread-0 : 購票成功,餘票為:99
Thread-0 : 購票成功,餘票為:98
Thread-2 : 購票成功,餘票為:97
.....
Thread-2 : 購票成功,餘票為:7
Thread-0 : 購票成功,餘票為:6
Thread-0 : 購票成功,餘票為:5
Thread-1 : 購票成功,餘票為:4
Thread-1 : 購票成功,餘票為:3
Thread-0 : 購票成功,餘票為:2
Thread-0 : 購票成功,餘票為:1
Thread-2 : 購票成功,餘票為:0

2)同步方法

package com.lxj.juc;

public class TestSync {

	public static void main(String[] args) {
		Ticket ticket = new Ticket();
		new Thread(ticket).start();
		new Thread(ticket).start();
		new Thread(ticket).start();
	}

}

class Ticket implements Runnable {

	private int ticket = 100;

	@Override
	public void run() {
		while (true) {
			if (ticket > 0) {
				int i = purchase();
				if(i == 0) {
					break;
				}
			}else {
				break;
			}
		}
	}

	private synchronized int purchase() {
		if (ticket > 0) {
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + " : 購票成功,餘票為:" + --ticket);
		}else {
			return 0;
		}
		return 1;
	}

}
執行結果:
Thread-0 : 購票成功,餘票為:99
Thread-0 : 購票成功,餘票為:98
Thread-0 : 購票成功,餘票為:97
Thread-2 : 購票成功,餘票為:96
Thread-1 : 購票成功,餘票為:95
....
Thread-1 : 購票成功,餘票為:8
Thread-2 : 購票成功,餘票為:7
Thread-2 : 購票成功,餘票為:6
Thread-0 : 購票成功,餘票為:5
Thread-0 : 購票成功,餘票為:4
Thread-0 : 購票成功,餘票為:3
Thread-2 : 購票成功,餘票為:2
Thread-1 : 購票成功,餘票為:1
Thread-2 : 購票成功,餘票為:0


3)同步鎖lock

package com.lxj.juc;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TestSync {

	public static void main(String[] args) {
		Ticket ticket = new Ticket();
		new Thread(ticket).start();
		new Thread(ticket).start();
		new Thread(ticket).start();
	}

}

class Ticket implements Runnable {

	private int ticket = 100;

    private Lock lock = new ReentrantLock();
	
	@Override
	public void run() {
		while (true) {
			lock.lock(); //上鎖
			try {
				if (ticket > 0) {
					try {
						Thread.sleep(200);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName() + " : 購票成功,餘票為:" + --ticket);
				}else {
					break;
				}
			} finally {
				lock.unlock(); //解鎖
			}
		}
	}


}
執行結果:
Thread-0 : 購票成功,餘票為:99
Thread-1 : 購票成功,餘票為:98
Thread-1 : 購票成功,餘票為:97
Thread-1 : 購票成功,餘票為:96
Thread-1 : 購票成功,餘票為:95
Thread-2 : 購票成功,餘票為:94
......
Thread-0 : 購票成功,餘票為:6
Thread-0 : 購票成功,餘票為:5
Thread-1 : 購票成功,餘票為:4
Thread-2 : 購票成功,餘票為:3
Thread-2 : 購票成功,餘票為:2
Thread-2 : 購票成功,餘票為:1
Thread-2 : 購票成功,餘票為:0

注意使用同步鎖一定要記得關閉鎖,放在try{}finally{}中。