1. 程式人生 > >java執行緒學習(七):JDK併發包之Condition條件

java執行緒學習(七):JDK併發包之Condition條件

在上一篇中,我們學習了JDK併發包的重入鎖的使用,然而執行緒流程的處理,並不單單是上鎖,中斷的操作,還有之前學到過的等待wait(),通知notify()等等,但wait(),notify()是與synchronized()搭配使用的。對應於jdk併發包,我們也有相應的類去使用,那就是重入鎖的好搭檔——Condition介面。

Condition介面有以下方法:

public interface Condition {
	void await() throws InterruptedException;
	void awaitUninterruptibly();
	long
awaitNanos(long var1) throws InterruptedException; boolean await(long var1, TimeUnit var3) throws InterruptedException; boolean awaitUntil(Date var1) throws InterruptedException; void signal(); void signalAll(); }

Condition的特性:

  • Condition中的await()方法相當於Object的wait()方法,Condition中的signal()方法相當於Object的notify()方法,Condition中的signalAll()相當於Object的notifyAll()方法。不同的是,Object中的這些方法是和同步鎖捆綁使用的;而Condition是需要與互斥鎖/共享鎖捆綁使用的。
  • Condition它更強大的地方在於:能夠更加精細的控制多執行緒的休眠與喚醒。對於同一個鎖,我們可以建立多個Condition,在不同的情況下使用不同的Condition。
    例如,假如多執行緒讀/寫同一個緩衝區:當向緩衝區中寫入資料之後,喚醒"讀執行緒";當從緩衝區讀出資料之後,喚醒"寫執行緒";並且當緩衝區滿的時候,"寫執行緒"需要等待;當緩衝區為空時,"讀執行緒"需要等待。
  • 如果採用Object類中的wait(), notify(), notifyAll()實現該緩衝區,當向緩衝區寫入資料之後需要喚醒"讀執行緒"時,不可能通過notify()或notifyAll()明確的指定喚醒"讀執行緒",而只能通過notifyAll喚醒所有執行緒(但是notifyAll無法區分喚醒的執行緒是讀執行緒,還是寫執行緒)。 但是,通過Condition,就能明確的指定喚醒讀執行緒。

注:建議檢視之前的文章去了解下wait和notify的使用,後續對Condition的使用是很有幫助的。

Condition的使用(Condition是需要配合重入鎖使用的)
舉個例子:

package stop_demo;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 例子說明:
 * add()方法:當集合長度為10時,就掛起當前的執行緒, 讓其他執行緒先走。否則就會新增一條資訊,然後喚起執行sub()的執行緒
 * sub()方法:當長度為0時,同理操作
 * 
 * @author fei
 *
 */
public class Condition_demo implements Runnable {

	private final static Lock lock = new ReentrantLock();

	private final static Condition addCondition = lock.newCondition();

	private final static Condition subCondition = lock.newCondition();


	private static int num = 0;
	private static List<String> lists = new LinkedList<String>();
	private boolean flag;

	public Condition_demo(boolean flag){
		this.flag=flag;

	}

	@Override
	public void run() {
		if (flag) {
			add();//執行執行緒新增器
		}
		else {
			sub();//執行執行緒減數器
		}

	}

	public void add() {
		lock.lock();

		try {
			while(lists.size() == 10) {//當集合已滿,則"新增"執行緒等待
				addCondition.await();//滿了就掛起來
			}

			num++;
			lists.add("add Banana" + num);
			System.out.println("處於‘增加’執行緒方法  集合長度為:   " + lists.size());
			System.out.println("The Current Thread is " + Thread.currentThread().getName());
			System.out.println("==============================");
			this.subCondition.signal();//喚起“減少”執行緒

		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {//釋放鎖
			lock.unlock();
		}
	}


	public void sub() {
		lock.lock();
		try {
		
			while(lists.size() == 0) {//當集合為空時,"減少"執行緒等待
				System.out.println("‘減少’執行緒已掛起~~~~");
				subCondition.await();
			}
			String str = lists.get(0);
			lists.remove(0);
			System.out.println("處於‘減少’執行緒方法:  集合內容為:  [" + str + "]");
			System.out.println("The Current Thread is " + Thread.currentThread().getName());
			System.out.println("==============================");
			num--;
			addCondition.signal();//喚起“增加”執行緒

		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	public static void main(String[] args) throws InterruptedException {
		Condition_demo task1 = new Condition_demo(true);
		Condition_demo task2 = new Condition_demo(false);

		Thread t1 = new Thread(task1);
		Thread t2 = new Thread(task1);
		Thread t3 = new Thread(task1);
		Thread t4 = new Thread(task1);
		Thread t5 = new Thread(task1);
		Thread t7 = new Thread(task2);
		Thread t6 = new Thread(task2);
		Thread t8 = new Thread(task2);
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		t5.start();
		t6.start();
		t7.start();
		t8.start();

	}
}

可以複製當前例子到demo中,執行後就會發現,condition和lock真是個好搭檔!!