线程间通信:Condition | 信号量:Semaphore

线程间通信:Condition

对于线程间通信,大家最熟悉的莫过于Object.wait()、Object.notify()了。Condition的使用与前面的方法类似。

    void await() throws InterruptedException;
    void awaitUninterruptibly();
    long awaitNanos(long nanosTimeout) throws InterruptedException;
    boolean await(long time, TimeUnit unit) throws InterruptedException;
    boolean awaitUntil(Date deadline) throws InterruptedException;
    void signal();
    void signalAll();
  • await():当前线程调用后,释放锁资源,进入等待状态;当其他线程调用signal()或者signalAll()时,线程会重新获得锁并继续执行。
  • awaitUninterruptibly():与await()方法的唯一区别就是,不响应中断信号。(await是响应中断的)
  • signal():唤醒一个等待中的线程,类似于Object.notify(),signalAll()则是唤醒所有等待中的线程,然后让其竞争执行。
public class ReenterLockCondition implements Runnable {

	public static ReentrantLock lock = new ReentrantLock();
	public static Condition condition = lock.newCondition();

	@Override
	public void run() {
		try {
			lock.lock();
			System.out.println("Thread is await");
			condition.await();
			System.out.println("Thread is going on");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	public static void main(String[] args) throws InterruptedException {
		ReenterLockCondition r1 = new ReenterLockCondition();
		Thread t1 = new Thread(r1);
		t1.start();
		Thread.sleep(2000);
		// 通知线程t1继续执行
		lock.lock();
		condition.signal();
		lock.unlock();
	}
}

上述示例代码可以看出,在t1执行的过程中,调用了await(),然后主线程中调用了signal(),让其继续执行。

信号量:Semaphore

信号量这个名字乍一看来和线程同步控制没有任何关系,但是信号量的功能比ReentrantLock还要强大。当我们new ReentrantLock()的时候,此时我们就有了一把锁,而信号量则是可以自己定义这个锁的个数。

Semaphore类提供了一下两个构造方法:

public Semaphore(int permits);
public Semaphore(int permits, boolean fair);

从构造方法可以看出,创建有容量的锁对象,同时还可以让其公平。其常用方法如下:

// 获取一个锁(响应中断)
public void acquire() throws InterruptedException;
// 获取一个锁(不响应中断)
public void acquireUninterruptibly();
// 尝试获得一个锁,若获取不到则立即返回false
public boolean tryAcquire();
// 尝试获得一个锁,并设置了最大等待时间
public boolean tryAcquire(long timeout, TimeUnit unit);
// 释放一个锁
public void release();
// 获得n个锁(响应中断)
public void acquire(int permits) throws InterruptedException;
// 获得n个锁(不响应中断)
public void acquireUninterruptibly(int permits);
// 获得n个锁,若获取不到则立即返回false
public boolean tryAcquire(int permits);
// 获得n个锁,并设置了最大等待时间
public boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException;
// 释放n个锁
public void release(int permits);

下面展示一个简单的例子:

public class SemapDemo implements Runnable {
	
	final Semaphore semp = new Semaphore(5);

	@Override
	public void run() {
		try {
			semp.acquire();
			// 模拟耗时操作
			Thread.sleep(2000);
			System.out.println(Thread.currentThread().getId() + ": done!");
			semp.release();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		ExecutorService exec = Executors.newFixedThreadPool(20);
		final SemapDemo demo = new SemapDemo();
		for(int i = 0; i < 20; i++) {
			exec.submit(demo);
		}
	}

}

上面代码创建了容量为5的锁,故每次打印的"done!"个数都是5。