利用JAVA線程安全隊列簡單實現讀者寫者問題。

常見的操做系統教科書中,會使用互斥鎖來實現讀者線程和寫者線程的同步問題,可是在JDK5推出線程安全隊列以後,將該問題變得異常簡單。 java

java.util.concurrent.ConcurrentLinkedQueue 是線程安全的非阻塞隊列,其實很容易想到,非阻塞隊列當線程須要等待的時候,則不會阻塞等待,而是直接根據狀況返回。 安全

java.util.concurrent.LinkedBlockingQueue 是線程安全的阻塞隊列,該隊列可以在不少狀況下對線程進行阻塞,好比隊列爲空時調用take() 方法,改方法是從隊首取得對象,若是對象不存在,則會阻塞等待,直到有可取的對象以後則喚醒該線程並取走隊首對象。一樣,這種阻塞隊列還有put() 這樣的阻塞方法:在放入對象到隊尾的時候若是隊列不可用,則阻塞等待,知道隊列可用。而非阻塞隊列則沒有這樣的阻塞方法。 ide


下面這個例子,是使用非阻塞隊列實現讀者寫者問題的簡單例子: this

package nonblockingqueueconpro;

import java.util.concurrent.ConcurrentLinkedQueue;

public class MainThread {
	public static void main(String args[]) {
		ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<String>();

		for (int i = 0; i < 2; i++) {
			Productor task = new Productor(queue);
			Thread t = new Thread(task, "生產者線程" + i);
			t.start();
		}

		for (int i = 0; i < 2; i++) {
			Consumer task = new Consumer(queue);
			Thread t = new Thread(task, "消費者線程" + i);
			t.start();
		}
	}
}

class Consumer implements Runnable {
	private ConcurrentLinkedQueue<String> queue;

	public Consumer(ConcurrentLinkedQueue<String> queue) {
		this.queue = queue;
	}

	@Override
	public void run() {
		while (true) {
			try {
				Thread.currentThread().sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

			System.out.println("消費者-->  " + queue.poll());
		}

	}
}

class Productor implements Runnable {

	private ConcurrentLinkedQueue<String> queue;

	public Productor(ConcurrentLinkedQueue<String> queue) {
		this.queue = queue;
	}

	@Override
	public void run() {
		while (true) {
			try {
				Thread.currentThread().sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			String content = String.valueOf(System.currentTimeMillis());
			System.out.println("生產者==>  " + content);
			queue.add(content);
		}

	}

}



能夠看到,消費者線程有可能會取不到對象的狀況(隊列爲空),則poll() 方法返回空,運行結果片斷以下:

消費者-->  null
消費者-->  null
生產者==>  1439301233285
生產者==>  1439301233284
消費者-->  1439301233284
生產者==>  1439301234289
生產者==>  1439301234289
......



而使用阻塞隊列設計的例子,消費者不會出現返回null的狀況,若是隊列爲空時,消費者線程會進行等待,代碼以下: 操作系統

package blockingqueueconpro;

import java.util.concurrent.LinkedBlockingQueue;

public class MainThread {
	public static void main(String args[]) {
		LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<String>();

		for (int i = 0; i < 2; i++) {
			Productor task = new Productor(queue);
			Thread t = new Thread(task, "生產者線程" + i);
			t.start();
		}

		for (int i = 0; i < 2; i++) {
			Consumer task = new Consumer(queue);
			Thread t = new Thread(task, "消費者線程" + i);
			t.start();
		}
	}
}

class Productor implements Runnable {

	private LinkedBlockingQueue<String> queue;

	public Productor(LinkedBlockingQueue<String> queue) {
		this.queue = queue;
	}

	@Override
	public void run() {
		while (true) {
			try {
				Thread.currentThread().sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			String content = String.valueOf(System.currentTimeMillis());
			System.out.println("生產者==>  " + content);
			queue.add(content);
		}

	}

}

class Consumer implements Runnable {
	private LinkedBlockingQueue<String> queue;

	public Consumer(LinkedBlockingQueue<String> queue) {
		this.queue = queue;
	}

	@Override
	public void run() {
		while (true) {
			try {
				Thread.currentThread().sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

			try {
				System.out.println("消費者-->  " + queue.take());
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

	}
}



運行結果以下:

生產者==>  1439301385710
生產者==>  1439301385710
消費者-->  1439301385710
消費者-->  1439301385710
生產者==>  1439301386716
生產者==>  1439301386716
......



總結:在平常開發中,須要線程安全的狀況下,java.util.concurrent 包下面的不少類可以解決問題,這比起本身實現對象鎖和同步來講,代碼更簡單,也更安全。 線程

相關文章
相關標籤/搜索