Java 线程同步工具类

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 两两线程之间数据交换,并且能够在交换线程超时后,不再等待数据交换,依旧可以继续运行后续代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值