Java多線程設計模式系列


通過幾天的認真閱讀,發現這是一本難得一見的好書,為了加深鞏固學習成功,我打算將書中的例子全部自己實現一遍,特此記錄下來也方便其他朋友學習。

 

第一章,java語言的線程

單線程程序:打印10000次good字符串

public class SingleThreadSample {
	public static void main(String[] args) {
		for(int i=0; i< 10000; i++){
			System.out.print("good!");
		}
	}
}

嚴格的說並不是只有一個線程在操作,還有其他的線程在非java處理系統上運行,比如gc,gui相關的線程等。

 

第一個多線程程序:實現了交替打印good和nice的功能

public class MyThreadTest {

	public static void main(String[] args) {
		MyThread t = new MyThread();
		t.start();

		for (int i = 0; i < 10000; i++) {
			System.out.println("good!");
		}
	}
}

class MyThread extends Thread {

	@Override
	public void run() {
		for (int i = 0; i < 10000; i++) {
			System.out.println("nice!");
		}
	}
}

 

這里加入一個並發和並行概念的區別,並發是concurrent,是指多個線程在同一個cpu上切換進行執行。並行是parallel,指多個線程是在各自的cpu上同時執行的。

我們增強一下剛才的多線程例子,把打印的字符串變成通過參數傳遞。

public class MyThread2Test {
	public static void main(String[] args) {
		MyThread2 t1 = new MyThread2("good!");
		MyThread2 t2 = new MyThread2("nice!");
		
		t1.start();
		t2.start();
	}
	
}

class MyThread2 extends Thread {
	private String message;

	public MyThread2(String message) {
		this.message = message;
	}

	@Override
	public void run() {
		for (int i = 0; i < 10000; i++) {
			System.out.println(message);
		}
	}
}

  

剛才是通過集成Thread抽象類的子類方式實現多線程,另外還可以通過Runnable接口的方式,例子如下:

public class MyThread3Test {
	public static void main(String[] args) {
		MyThread3 t1 = new MyThread3("good!");
		MyThread3 t2 = new MyThread3("nice!");
		
		new Thread(t1).start();
		new Thread(t2).start();
	}
}

class MyThread3 implements Runnable {
	private String message;

	public MyThread3(String message) {
		this.message = message;
	}

	@Override
	public void run() {
		for (int i = 0; i < 10000; i++) {
			System.out.println(message);
		}
	}
}

  

啟動和執行多線程已經說完了,那么該說說如何讓線程休息休息。

第一種方式是通過Thread.sleep(ms)方法,需要注意的是這個方法有一個重載Thread.sleep(ms,ns),可以把停止的時間控制到納秒級。

另外Thread.yield()方法也可以在循環體中使用,表示如果沒有cpu時間則將當前線程切換到其他子線程,可以簡單理解成Thread.sleep(0);

 不過Thread.sleep會拋出InterruptedException異常,Thread.yield不會。

 

下面在說說線程互斥,還是剛才的例子,如果我打算讓程序執行10000次打印的過程是一個整體,執行過程中不允許切換到其他子線程,那么就需要使用Synchronzed關鍵字。

public class MyThreadMutualTest {
	public static void main(String[] args) {
		PrintMessage pmsg = new PrintMessage();

		new MyThreadMutual(pmsg,"good").start();
		new MyThreadMutual(pmsg,"nice").start();
	}
}

class MyThreadMutual extends Thread {
	private String message;
	private PrintMessage printMessage;

	public MyThreadMutual(PrintMessage printMessage,String message) {
		this.printMessage = printMessage;
		this.message=message;
	}

	@Override
	public void run() {
		printMessage.show(message);
	}
}

class PrintMessage {

	public synchronized void show(String msg) {
		for (int i = 0; i < 10000; i++) {
			System.out.println(msg);
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

  

 

接下來講一下線程的協調,主要有三個方法:wait() notify() notifyAll()

這三個方法都是object類的方法,可以理解成一個休息室,調用obj.wait()方法表示當前執行的線程進入休息室,休息室里可能會有多個線程,如果沒有其他線程給休息室發消息通知它們可以出去了,這些線程就會一直在里面休息。

當調用obj.notify()方法,表示休息室中可以有一個線程退出,如果里面有多個線程,會隨機選取一個,而obj.notifyAll()表示所有的線程都可以退出休息室。

現在把上面的例子修改一下,想打印10次good再打印10次nice,這樣交替執行。

public class ThreadMutualTest2 {
	public static void main(String[] args) {
		Object obj = new Object();
		MyThreadMutualA a = new MyThreadMutualA("nice", obj);
		MyThreadMutualB b = new MyThreadMutualB("good", obj);
		
		a.start();
		b.start();
	}
}

class MyThreadMutualA extends Thread {
	private Object obj;
	private String message;
	
	public MyThreadMutualA(String message, Object obj) {
		this.message=message;
		this.obj=obj;
	}

	@Override
	public  void run() {
		synchronized(obj){
			for(int i=1; i<100; i++){
				System.out.println(message);
				
				if(i%5==0){
					obj.notify();
					
					try {
						obj.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
			
			obj.notify();
		}
	}
}

class MyThreadMutualB extends Thread {

	private Object obj;
	private String message;
	
	public MyThreadMutualB(String message, Object obj) {
		this.message=message;
		this.obj=obj;
	}

	@Override
	public synchronized void run() {
		synchronized(obj){
			for(int i=1; i<100; i++){
				System.out.println(message);
				if(i%5==0){
					obj.notify();
					
					try {
						obj.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
			
			obj.notify();
		}
	}
}

  

這段代碼廢了好大勁啊,同步互斥是多線程最復雜的最核心的部分了。

 


免責聲明!

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



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