CountDownLatch
解释一下这张图
新建一个coundDownLatch,值为3
线程A调用coundDownLatch的await方法,线程将被阻塞
线程1执行的实现调用coundDownLatch.countDown方法,则coundDownLatch的值减一,变成2
知道coundDownLatch的值为0,线程A恢复运行
public class CountDownLatchTest {
private final static int threadCount = 200;
public static void main(String[] args) throws InterruptedException {
ExecutorService pool = Executors.newCachedThreadPool();
//新建一个CountDownLatch
final CountDownLatch cdl = new CountDownLatch(threadCount);
for(int i = 0; i < threadCount; ++i) {
final int threadNum = i;
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println(threadNum);
//对每个线程进行减一操作
cdl.countDown();
}
});
}
//此处await也可以添加参数,表示等待的时间
cdl.await();
pool.shutdown();
System.out.println("end");
}
}
Semaphore
相当于一个信号量,用来控制同一时间多少线程并发执行
private final static int threadCount = 200;
public static void main(String[] args) throws InterruptedException {
final Semaphore seam = new Semaphore(3);
ExecutorService pool = Executors.newCachedThreadPool();
for(int i = 0; i < threadCount; ++i) {
final int threadNum = i;
pool.execute(new Runnable() {
@Override
public void run() {
try {
//获得许可
seam.acquire();
System.out.println(threadNum);
Thread.sleep(1000);
//释放许可
seam.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
pool.shutdown();
}
//acquire和release还有下面这些用法
//一次获取2个
seam.acquire(2);
//尝试获取1个
if(seam.tryAcquire()) {}
//尝试获取2个
if(seam.tryAcquire(2)) {}
//尝试获取1个,超时时间为1000ms
if(seam.tryAcquire(1000, TimeUnit.MILLISECONDS)) {}
//尝试获取10个,超时时间为1000ms
if(seam.tryAcquire(10, 1000, TimeUnit.MILLISECONDS)) {}
//释放10个
seam.release(10);
CyclicBarrier
与CountDownLatch类似,但是这个是相互等待,直到有指定数量线程准备完毕,然后一起执行
具体的看演示代码
public class CyclicBarrierExample1 {
//创建CyclicBarrier 对象,目标数值为5
private static CyclicBarrier cb = new CyclicBarrier(5);
public static void main(String[] args) throws InterruptedException {
ExecutorService pool = Executors.newCachedThreadPool();
for(int i = 0; i < 10; ++i) {
final int threadNum = i;
//这里让当前线程暂停,然后一个一个显示,要不然线程会一起运行会一起显示
Thread.sleep(1000);
pool.execute(new Runnable() {
@Override
public void run() {
try {
race(threadNum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
});
}
pool.shutdown();
}
private static void race(int threadNum) throws InterruptedException, BrokenBarrierException {
//模拟等待,这里可以不写
Thread.sleep(1000);
System.out.println(threadNum + " is ready");
//调用wait方法,让值加1,当有5个线程执行这个方法后,则会输出continue
cb.await();
System.out.println(threadNum + " continue");
}
}
//await方法也可以设定超时时间,超过后就直接执行,不必等待
private static void race(int threadNum) throws InterruptedException {
Thread.sleep(1000);
System.out.println(threadNum + " is ready");
//超时后会抛出异常,要try住,要不然后面的代码无法执行
try {
cb.await(2000, TimeUnit.MILLISECONDS);
} catch (BrokenBarrierException e) {
//e.printStackTrace();
} catch (TimeoutException e) {
//e.printStackTrace();
}
System.out.println(threadNum + " continue");
}
//CaclicBarrier还可定义一个方法, 再达到指定数值后优先执行
private static CyclicBarrier cb = new CyclicBarrier(5, new Runnable() {
@Override
//在达到5后会执行这个方法,执行一次,然后再去执行之前的5个线程的方法
public void run() {
System.out.println("callback");
}
});
ReentrantLock
还是之前那个计数的例子
private static void add() {
//显示的加锁和解锁即可
lock.lock();
++count;
lock.unlock();
}
//默认是不公平的锁
Lock lock = new ReentrantLock();
public ReentrantLock() {
sync = new NonfairSync();
}
//参数了加true即为公平锁,获得锁的顺序,按照线程申请获得锁的顺序
Lock lock = new ReentrantLock(true);
//看下面的例子
public class LockExample2 {
//请求总数
public static int clientTotal = 10;
//此时为公平锁
private final static Lock lock = new ReentrantLock(true);
public static void main(String[] args) throws InterruptedException {
ExecutorService es = Executors.newCachedThreadPool();
//信号量
for(int i = 0; i < clientTotal; ++i) {
final int num = i;
es.execute(new Runnable() {
@Override
public void run() {
show(num);
}
});
}
es.shutdown();
}
private static void show(int num) {
//表示开始申请获得锁
System.out.println(num + "---进入");
lock.lock();
//真正获得了锁
System.out.println(num + "---获得锁");
System.out.println(num);
lock.unlock();
}
}
//输出结果,进入顺序和获得锁的顺序一致
1---进入
4---进入
5---进入
3---进入
8---进入
0---进入
2---进入
7---进入
9---进入
6---进入
1---获得锁
4---获得锁
5---获得锁
3---获得锁
8---获得锁
0---获得锁
2---获得锁
7---获得锁
9---获得锁
6---获得锁
//改成非公平锁,发现获得锁的顺序和进入的顺序不一致
2---进入
3---进入
1---进入
0---进入
5---进入
2---获得锁
4---进入
8---进入
5---获得锁
6---进入
7---进入
9---进入
3---获得锁
1---获得锁
0---获得锁
4---获得锁
8---获得锁
6---获得锁
7---获得锁
9---获得锁
//lock.lockInterruptibly()和lock.lock();
//lock不会去处理中断,在获取到锁之后才会处理中断
//lockInterruptibly在获取锁的过程中就会响应中断
public static void main(String[] args) throws InterruptedException {
final Lock lock=new ReentrantLock();
//main函数先获取锁
lock.lock();
Thread.sleep(1000);
Thread t1=new Thread(new Runnable(){
@Override
public void run() {
try {
//这里再获取锁线程中断会抛出异常,改成lock.lock()就不会异常,会先获取所再处理异常
lock.lockInterruptibly();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" interrupted.");
}
});
t1.start();
Thread.sleep(1000);
//这里去中断线程,让她抛出异常
t1.interrupt();
}
//Lock的await对应于Object.wait,signal对应于Object.notify,signalAll对应于Object.notifyAll。
BlockingQueue
具体的实现类有ArrayBlockingQueue,LinkedBlockingQueue,DelayQueue,PriorityBlockingQueue,SynchronousQueue
可以看看这个文章: https://www.cnblogs.com/tjudzj/p/4454490.html
//ArrayBlockingQueue实现生产者消费者
public class ArrayBlockingQueueTest {
public static final ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(5);
public static final int total = 100;
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
// 消费者
while (true) {
try {
Thread.sleep(1000);
// 使用take方法当队列为空会阻塞
Integer take = queue.take();
System.out.println(take);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
// 生产者
for (int i = 0; i < total; ++i) {
try {
//put方法当容量满了会阻塞
queue.put(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}