1. 程式人生 > >多執行緒案例 Java

多執行緒案例 Java

1、購票(不安全策略)

程式碼片段:

public class Main {
    private static int ticket = 10;
    public static void main(String[] args) {
    	Runnable r = new Runnable() {
    		public void run() {
    			while(ticket > 0) {
    				try {
    					ticket--;
    					Thread.sleep(1000);
    					System.out.println("賣出了一張票,還剩下"+ticket+"張票");
    				}catch (Exception e) {
    					e.printStackTrace();
    				}
    				
    			}
    		}
    	};
    	new Thread(r).start();
    	new Thread(r).start();
    	new Thread(r).start();
    	new Thread(r).start();
    }
}

顯示結果:

賣出了一張票,還剩下6張票
賣出了一張票,還剩下5張票
賣出了一張票,還剩下5張票
賣出了一張票,還剩下5張票
賣出了一張票,還剩下2張票
賣出了一張票,還剩下2張票
賣出了一張票,還剩下2張票
賣出了一張票,還剩下2張票
賣出了一張票,還剩下0張票
賣出了一張票,還剩下0張票

2、購票(安全策略)

  • 給方法加入synchronized解決執行緒不安全問題

程式碼片段:

public class Main {
    private static int ticket = 10;
    public static void main(String[] args) {
    	Runnable r = new Runnable() {
    		public synchronized void run() {
    			while(ticket > 0) {
    				try {
    					ticket--;
    					Thread.sleep(1000);
    					System.out.println("賣出了一張票,還剩下"+ticket+"張票");
    				}catch (Exception e) {
    					e.printStackTrace();
    				}
    				
    			}
    		}
    	};
    	new Thread(r).start();
    	new Thread(r).start();
    	new Thread(r).start();
    	new Thread(r).start();
    }
}

顯示結果:

賣出了一張票,還剩下9張票
賣出了一張票,還剩下8張票
賣出了一張票,還剩下7張票
賣出了一張票,還剩下6張票
賣出了一張票,還剩下5張票
賣出了一張票,還剩下4張票
賣出了一張票,還剩下3張票
賣出了一張票,還剩下2張票
賣出了一張票,還剩下1張票
賣出了一張票,還剩下0張票

注:第一個執行緒進入run()後,其他程序無法進入,直到第一個執行緒執行完畢才允許其他程序進入,而此時ticket已經為0,其他程序不能進入迴圈體,因此,退出。

其中,形如synchronized (Main.class) {}包含程式碼塊的結構也能達到同樣的效果。

3、wait()和notify()

程式碼片段:

public class Main {
	public static void main(String[] args) {
		new Thread() {
			public void run() {
				synchronized (Main.class) {
					System.out.println("T1 start!");
					try {
						Main.class.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println("T1 end!");
				}
			}
		}.start();
		new Thread() {
			public void run() {
				synchronized (Main.class) {
					System.out.println("T2 start!");
					Main.class.notify(); //喚醒
					System.out.println("T2 end!");
				}
			}
		}.start();
	}
}

結果顯示:

T1 start!
T2 start!
T2 end!
T1 end!

解析:wait()和notify()一系列的方法,是屬於物件的,不是屬於執行緒的。它們用線上程同步時,synchronized語句塊中。

wait()方法可以使執行緒進入等待狀態,而notify()可以使等待的狀態喚醒。這樣的同步機制十分適合生產者、消費者模式:消費者消費某個資源,而生產者生產該資源。當該資源缺失時,消費者呼叫wait()方法進行自我阻塞,等待生產者的生產;生產者生產完畢後呼叫notify/notifyAll()喚醒消費者進行消費。

4、wait()notify()精細控制

程式碼片段:

public class Main {
	public static void main(String[] args) {
		final Object object = new Object();
		new Thread() {
			public void run() {
				synchronized (object) {
					System.out.println("T1 start!");
					try {
						object.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println("T1 end!");
				}
			}
		}.start();
		new Thread() {
			public void run() {
				synchronized (object) {
					System.out.println("T2 start!");
					object.notify();
					System.out.println("T2 end!");
				}
			}
		}.start();;
		new Thread() {
			public void run() {
				synchronized (object) {
					System.out.println("T3 start!");
					object.notify();
					System.out.println("T3 end!");
				}
			}
		}.start();;
		new Thread() {
			public void run() {
				synchronized (object) {
					System.out.println("T4 start!");
					try {
						object.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println("T4 end!");
				}
			}
		}.start();
	}
}

 

結果顯示:

T1 start!
T2 start!
T2 end!
T1 end!
T3 start!
T3 end!
T4 start!

很容易看出來,T4,它啟動了,但是wait了,後面已經沒有執行緒了,它的wait永遠不會有執行緒幫它notify了!於是,T4 (T4 end!沒法執行到)它就這麼等著!