Semaphore
字面含义为信号量,Semaphore可以控制同时访问的线程个数,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可 一个有味道的解释:(相当于上茅坑,同时只能固定蹲坑数量的线程工作,其他线程只能等待处于蹲坑中的线程结束它们的工作,才能前去填补它们的蹲坑空缺继续工作)
/*
* @since 1.5
*/
public class Semaphore{
/** All mechanics via AbstractQueuedSynchronizer subclass */
private final Sync sync;
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
//获取许可
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
//获取指定数量的许可
public void acquire(int permits) throws InterruptedException {
if (permits < 0) throw new IllegalArgumentException();
sync.acquireSharedInterruptibly(permits);
}
//返回可用许可数量
public int availablePermits() {
return sync.getPermits();
}
//释放许可
public void release() {
sync.releaseShared(1);
}
//释放指定数量的许可
public void release(int permits) {
if (permits < 0) throw new IllegalArgumentException();
sync.releaseShared(permits);
}
abstract static class Sync extends AbstractQueuedSynchronizer {
Sync(int permits) {
setState(permits);
}
final int getPermits() {
return getState();
}
}
/**
* NonFair version
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -2694183684443567898L;
NonfairSync(int permits) {
super(permits);
}
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
}
/**
* Fair version
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = 2014338818796000944L;
FairSync(int permits) {
super(permits);
}
protected int tryAcquireShared(int acquires) {
for (;;) {
if (hasQueuedPredecessors())
return -1;
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
}
}
Example
public class SemaphoreTest {
public static void main(String[] args) {
ExecutorService threadpool = Executors.newCachedThreadPool();
MyBusiness myBusiness = new MyBusiness();
for(int i=0;i<5;i++) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
myBusiness.output();
}
});
threadpool.execute(t);
}
threadpool.shutdown();
}
}
class MyBusiness{
Semaphore semaphore = new Semaphore(2);
public void output() {
String threadName = Thread.currentThread().getName();
try {
semaphore.acquire();
System.out.println(threadName + " coming in, There are currently " + (2-semaphore.availablePermits()) + " threads running" );
Thread.sleep(3000);
System.out.println(threadName + " ready end of runnning");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
semaphore.release();
System.out.println("There still have " + (2-semaphore.availablePermits()) + " running threads");
}
}
}
Result:
pool-1-thread-1 coming in, There are currently 1 threads running
pool-1-thread-2 coming in, There are currently 2 threads running
pool-1-thread-1 ready end of runnning
pool-1-thread-2 ready end of runnning
There still have 1 running threads
pool-1-thread-4 coming in, There are currently 2 threads running
pool-1-thread-3 coming in, There are currently 2 threads running
There still have 1 running threads
pool-1-thread-3 ready end of runnning
pool-1-thread-4 ready end of runnning
pool-1-thread-5 coming in, There are currently 2 threads running
There still have 1 running threads
There still have 1 running threads
pool-1-thread-5 ready end of runnning
There still have 0 running threads
总结: Semaphore其实和锁有点类似,它一般用于控制对某组资源的访问权限。
CyclicBarrier
循环屏障,让一组线程都运行至某一状态后,再接着继续运行。并且此处的循环意味着CyclicBarrier可以被重复使用,可以设置多处屏障。
public class CyclicBarrier {
private static class Generation {
boolean broken = false;
}
/** The lock for guarding barrier entry */
private final ReentrantLock lock = new ReentrantLock();
/** Condition to wait on until tripped */
private final Condition trip = lock.newCondition();
/** The number of parties */
private final int parties;
/* The command to run when tripped */
private final Runnable barrierCommand;
/** The current generation */
private Generation generation = new Generation();
//参数parties指让多少个线程或者任务等待至barrier状态;
public CyclicBarrier(int parties) {
this(parties, null);
}
//参数barrierAction为当这些线程都达到barrier状态时会执行的内容
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
//比较常用,用来挂起当前线程,直至所有线程都到达barrier状态再同时执行后续任务
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
//让这些线程等待至一定的时间,如果还有线程没有到达barrier状态就直接让到达barrier的线程执行后续任务
public int await(long timeout, TimeUnit unit)
throws InterruptedException,
BrokenBarrierException,
TimeoutException {
return dowait(true, unit.toNanos(timeout));
}
}
Example
public class CyclicBarrierTest {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newCachedThreadPool();
MyBusiness2 myBusiness2 = new MyBusiness2();
for(int i=0;i<3;i++) {
Thread thread =new Thread(new Runnable() {
@Override
public void run() {
myBusiness2.output();
}
});
threadPool.execute(thread);
}
threadPool.shutdown();
}
}
class MyBusiness2{
CyclicBarrier cyclicBarrier = new CyclicBarrier(3,new Runnable() {
@Override
public void run() {
System.out.println("milestone break...");
}
});
public void output() {
String threadName = Thread.currentThread().getName();
try {
System.out.println(threadName + " coming to area 1");
cyclicBarrier.await();
System.out.println(threadName + " coming to area 2");
cyclicBarrier.await();
System.out.println(threadName + " coming to area 3");
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
Result:
pool-1-thread-1 coming to area 1
pool-1-thread-2 coming to area 1
pool-1-thread-3 coming to area 1
milestone break...
pool-1-thread-1 coming to area 2
pool-1-thread-3 coming to area 2
pool-1-thread-2 coming to area 2
milestone break...
pool-1-thread-2 coming to area 3
pool-1-thread-3 coming to area 3
pool-1-thread-1 coming to area 3
milestone break...
总结: CyclicBarrier 允许重复使用,并且在某些线程超时后,能够让未超时而处于等待状态的线程继续执行后续的内容。
CountDownLatch
CountDownLatch相当于一个倒计数器,可以等待多线程执行结束后,再回来继续执行当前的等待线程
/*
* @since 1.5
*/
public class CountDownLatch {
private final Sync sync;
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
//等待计数器结束
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
//等待计数器结束,如果超时计数器依旧未结束则跑出异常,不在等待直接继续执行当前等待线程代码
public boolean await(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
//计数器计数操作
public void countDown() {
sync.releaseShared(1);
}
//返回当前计数器计数内容
public long getCount() {
return sync.getCount();
}
private static final class Sync extends AbstractQueuedSynchronizer {
Sync(int count) {
setState(count);
}
int getCount() {
return getState();
}
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
}
}
Example
public class CountDownLatchTest {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newCachedThreadPool();
MyBusiness3 myBusiness3 =new MyBusiness3();
CountDownLatch answer =new CountDownLatch(3);
for(int i=0;i<3;i++) {
Runnable runnable = new Runnable() {
@Override
public void run() {
myBusiness3.output(answer);
}
};
threadPool.execute(runnable);
}
try {
System.out.println(Thread.currentThread().getName() + " waiting for the result....");
answer.await(); //等待倒计时
System.out.println(Thread.currentThread().getName() + " received all the result....");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
threadPool.shutdown();
}
}
class MyBusiness3{
public void output(CountDownLatch answer) {
String threadName = Thread.currentThread().getName();
try {
System.out.println(threadName + " ready...");
System.out.println(threadName + " completed all the operation and return the result...");
answer.countDown();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
总结: CountDownLatch 不能重复使用,设置计数,并且能够在某些线程超时后,几遍计数器尚未达到计数要求,依旧可以继续运行后续代码
Exchanger
能够帮助两个线程之间进行数据交换,双方会互相等待,直到交换结束才会继续各自的内容,不能一个线程与多个线程进行数据交换,只能两两之间交换
/*
* @since 1.5
*/
public class Exchanger<V> {
private final Participant participant;
private volatile Node[] arena;
private volatile Node slot;
private volatile int bound;
@sun.misc.Contended static final class Node {
int index; // Arena index
int bound; // Last recorded value of Exchanger.bound
int collides; // Number of CAS failures at current bound
int hash; // Pseudo-random for spins
Object item; // This thread's current item
volatile Object match; // Item provided by releasing thread
volatile Thread parked; // Set to this thread when parked, else null
}
/** The corresponding thread local class */
static final class Participant extends ThreadLocal<Node> {
public Node initialValue() { return new Node(); }
}
//普通交换
@SuppressWarnings("unchecked")
public V exchange(V x) throws InterruptedException {
Object v;
Object item = (x == null) ? NULL_ITEM : x; // translate null args
if ((arena != null ||
(v = slotExchange(item, false, 0L)) == null) &&
((Thread.interrupted() || // disambiguates null return
(v = arenaExchange(item, false, 0L)) == null)))
throw new InterruptedException();
return (v == NULL_ITEM) ? null : (V)v;
}
//允许交换等待超时,就不再等待,各自继续执行
@SuppressWarnings("unchecked")
public V exchange(V x, long timeout, TimeUnit unit)
throws InterruptedException, TimeoutException {
Object v;
Object item = (x == null) ? NULL_ITEM : x;
long ns = unit.toNanos(timeout);
if ((arena != null ||
(v = slotExchange(item, true, ns)) == null) &&
((Thread.interrupted() ||
(v = arenaExchange(item, true, ns)) == null)))
throw new InterruptedException();
if (v == TIMED_OUT)
throw new TimeoutException();
return (v == NULL_ITEM) ? null : (V)v;
}
// Unsafe mechanics
private static final sun.misc.Unsafe U;
private static final long BOUND;
private static final long SLOT;
private static final long MATCH;
private static final long BLOCKER;
private static final int ABASE;
static {
int s;
try {
U = sun.misc.Unsafe.getUnsafe();
Class<?> ek = Exchanger.class;
Class<?> nk = Node.class;
Class<?> ak = Node[].class;
Class<?> tk = Thread.class;
BOUND = U.objectFieldOffset
(ek.getDeclaredField("bound"));
SLOT = U.objectFieldOffset
(ek.getDeclaredField("slot"));
MATCH = U.objectFieldOffset
(nk.getDeclaredField("match"));
BLOCKER = U.objectFieldOffset
(tk.getDeclaredField("parkBlocker"));
s = U.arrayIndexScale(ak);
// ABASE absorbs padding in front of element 0
ABASE = U.arrayBaseOffset(ak) + (1 << ASHIFT);
} catch (Exception e) {
throw new Error(e);
}
if ((s & (s-1)) != 0 || s > (1 << ASHIFT))
throw new Error("Unsupported array scale");
}
}
Example
public class ExChangerTest {
public static void main(String[] args) {
Exchanger<String> exchanger = new Exchanger<String>();
MyBusiness4 myBusiness4 = new MyBusiness4();
new Thread(new Runnable() {
@Override
public void run() {
String tradedData = "AAAA";
myBusiness4.output(exchanger,tradedData);
}
}).start();
try {
String mainTradedData = "BBBB";
System.out.println(Thread.currentThread().getName() + " ready to exchange " + mainTradedData + " with other thread...");
String returnData = exchanger.exchange(mainTradedData);
System.out.println(Thread.currentThread().getName() + " received data is: " + returnData);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyBusiness4{
public void output(Exchanger exchanger,Object tradedData) {
String threadName = Thread.currentThread().getName();
try {
System.out.println(threadName+ " prepared to exchange " + tradedData +" with main thread... ");
String returnData = (String) exchanger.exchange(tradedData);
System.out.println(threadName+ " received data is: " + returnData);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
总结: Exchanger 两两线程之间数据交换,并且能够在交换线程超时后,不再等待数据交换,依旧可以继续运行后续代码