Semaphore和Exchanger

类Semaphore的主要作用是限制并发执行的线程数,它具有synchronized所不具有的强大功能,比如等待获取许可的同时可以加入等待时间,还有尝试是否可以持有锁等这类扩展功能,可以说它是强有力的控制并发线程个数的解决方案之一。
Exchanger是线程间传输数据的方式之一,而且在传输数据类型上没有任何限制。


Semaphore

Semaphore又称信号量,是操作系统中的一个概念,在Java并发编程中,信号量控制的是线程并发的数量。

构造函数

public Semaphore(int permits)

其中permits指同时运行的线程数量
可通过控制构造函数的permits,控制并发执行的线程数。

单线程示例

public class App {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(1);
        Single single = new Single(semaphore);
        for (int i = 0; i < 3; i ++) {
            new TestThread("Test-" + i, single).start();;
        }
    }
}
class TestThread extends Thread {
    private Single single;
    public TestThread(String name, Single single) {
        super(name);
        this.single = single;
    }
    @Override
    public void run() {
        single.test();
    }
    
}
class Single {
    private Semaphore semaphore;
    public Single(Semaphore semaphore) {
        this.semaphore = semaphore;
    }
    public void test() {
        try {
            semaphore.acquire();
            System.out.println(Thread.currentThread().getName() + " start at " + System.currentTimeMillis());
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + " stop at " + System.currentTimeMillis());
            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

运行结果

Test-0 start at 1524806263164
Test-0 stop at 1524806264166
Test-2 start at 1524806264166
Test-2 stop at 1524806265167
Test-1 start at 1524806265167
Test-1 stop at 1524806266167

方法介绍

acquire(int permits)还可以每次调用获取permits个许可。
acquireUninterruptibly()方法的作用是使进入等待许可的线程,不允许被中断。
availablePermits()返回当前可用的许可数量
drainPermits()获取并返回当前可用的许可数量,并将可用许可数置0
getQueueLength()获取等待许可的线程数
hasQueuedThreads()判断是否还有线程在等待这个许可
tryAcquire()尝试获取一个许可,无阻塞
tryAcquire(int permits)尝试获取permits个许可,无阻塞
tryAcquire(long timeout, TimeUnit unit)在指定时间内尝试获取一个许可以
tryAcquire(int permits, long timeout, TimeUnit unit)在指定时间内尝试获取permits个许可以

该类还支持公平和非公平许可:默认非公平

public Semaphore(int permits, boolean fair)

注:Semaphore并不能保证线程安全性,因此还是有可能会出现多个线程共同访问实例变量,导致出现脏数据的情况。

Exchanger

Exchanger的功能可以使2个线程之间传输数据,它比生产者/消费者模式产生的wait/notify要更加方便。

代码示例:

public class App {
    public static void main(String[] args) {
        Exchanger<String> exchanger = new Exchanger<>();
        Single single = new Single(exchanger);
        for (int i = 0; i < 2; i ++) {
            new TestThread("Test-" + i, single).start();;
        }
    }
}
class TestThread extends Thread {
    private Single single;
    public TestThread(String name, Single single) {
        super(name);
        this.single = single;
    }
    @Override
    public void run() {
        single.test(Thread.currentThread().getName());
    }
    
}
class Single {
    private Exchanger<String> exchanger;
    public Single(Exchanger<String> exchanger) {
        this.exchanger = exchanger;
    }
    public void test(String s) {
        try {
            System.out.println("send=" + s + " and receive=" + exchanger.exchange(s));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

运行结果

send=Test-0 and receive=Test-1
send=Test-1 and receive=Test-0

方法介绍

exchange(V x, long timeout, TimeUnit unit) 指定时间内没有其他线程获取数据,则出现超时异常