DownCountLatch 闭锁、多线程计数器
DownCountLatch :闭锁、多线程计数器
, 允许一个或多个线程,等待其他一组线程完成操作,再继续执行。
实例化DownCountLatch时候传入计数值
,当一个线程调用DownCountLatch的await方法的时候,这个线程会处于等待状态,其他线程任务中调用countDown方法,每次count减一,当count减到0为止,这个线程才会继续运行下去。
public CountDownLatch(int count)
//构造参数count为计数值,只有当count等于0的时候,等待状态的线程才能运行下去。
public void await()
//调用await()方法的线程会被挂起,直到count值为0才继续执行
public boolean await(long timeout, TimeUnit unit)
//和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
public void countDown()
//将count值减1
例子:
import java.util.concurrent.CountDownLatch;
public class CountDownLatchDemo {
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(10); // 1. 闭锁相当于一个计数器 // 10
MyRunnable myRunnable = new MyRunnable(countDownLatch);
long start = System.currentTimeMillis();
for (int i = 0; i <10; i++) {
new Thread(myRunnable).start();
}
// 3. 等待 计数器完成倒数操作, 才往下执行
try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); }
long end = System.currentTimeMillis();
Console.log("=====多线程,执行完成时间====>{}",end-start);
}
}
class MyRunnable implements Runnable {
private CountDownLatch latch;
public MyRunnable(CountDownLatch latch) {
this.latch = latch;
}
@Override
public void run() {
synchronized (MyRunnable.class) {
try {
for (int i =0; i<10000; i++){
Console.log(i);
}
} finally {
// 2. 每次执行线程任务, 计数器-1
latch.countDown();
}
}
}
}
CyclicBarrier 同步屏障
CyclicBarrier:一组线程,每个线程执行到的约定进度,就等待其他线程,等全部达到约定进度,才能继续执行各自线程任务的后续代码。
在实例化CyclicBarrier的时候会给它传一个int类型的参数N,只有N个线程都运行到CyclicBarrier的await方法的时候,这些线程才能继续运行下去。也就是说当前面N-1个线程运行到await方法的时候,N-1个线程都是等待的状态,只有当第N个线程运行await方法的时候,这N个线程才是处于就绪状态。
构造方法
public CyclicBarrier(int parties, Runnable barrierAction)
public CyclicBarrier(int parties)
方法
public int await()
public int await(long timeout, TimeUnit unit)
例子:
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierTest {
public static void main(String[] args) throws Exception{
CyclicBarrier cyclicBarrier = new CyclicBarrier(6,new Runnable(){
public void run(){
System.out.println("......................");
}
});
for(int i=0;i<6;i++){
RunnableTask runnableTask = new RunnableTask(cyclicBarrier);
Thread thread = new Thread(runnableTask,i+"");
thread.start();
}
}
}
class RunnableTask implements Runnable {
CyclicBarrier cyclicBarrier;
public RunnableDemoTwo(CyclicBarrier cyclicBarrier){
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run(){
try {
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName()+"========before");
cyclicBarrier.await();
System.out.println(Thread.currentThread().getName()+"========after");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Semaphore 信号量
一个信号量相当于持有一些许可(permits),线程可以调用Semaphore对象的acquire()方法获取一个许可,调用release()来归还一个许可。
Semaphore:在实例化Semaphore的时候,会传一个int类型的参数count,count就代表着Semaphore的信号池中有count个信号量,当一个线程调用Semaphore的acquire()或acquire(n)方法的时候就是获取1个或n个信号量,Semaphore的信号池就会减去这个线程获取到的信号量,当其他线程再调用acquire(m)方法获取信号量的时候,Semaphore信号池的中的信号量个数大于m,这个线程就可以继续运行,当信号池中的信号量小于m,这个线程就会处于等待状态,等待拥有信号量的线程调用release(n)方法释放自己所拥有的的信号,等信号池的信号量大于等于索要的信号量时,这个线程才会继续运行下去。
构造方法
public Semaphore(int permits)
参数permits表示该信号量拥有的许可数量,即同时可以允许多少线程进行访问
public Semaphore(int permits, boolean fair) ` //参数fair表示获取许可的时候是否是公平的,如果是公平的那么,当有多个线程要获取许可时,会按照线程来的先后顺序分配许可,否则,线程获得许可的顺序是不定的。这里在jdk中讲到 “一般而言,非公平时候的吞吐量要高于公平锁”,这是为什么呢?附上链接中的一段话:
非公平锁性能高于公平锁性能的原因:在恢复一个被挂起的线程与该线程真正运行之间存在着严重的延迟。假设线程A持有一个锁,并且线程B请求这个锁。由于锁被A持有,因此B将被挂起。当A释放锁时,B将被唤醒,因此B会再次尝试获取这个锁。与此同时,如果线程C也请求这个锁,那么C很可能会在B被完全唤醒之前获得、使用以及释放这个锁。这样就是一种双赢的局面:B获得锁的时刻并没有推迟,C更早的获得了锁,并且吞吐量也提高了。当持有锁的时间相对较长或者请求锁的平均时间间隔较长,应该使用公平锁。在这些情况下,插队带来的吞吐量提升(当锁处于可用状态时,线程却还处于被唤醒的过程中)可能不会出现。
获取许可
可以使用acquire()、acquire(int)、tryAcquire()等去获取许可,其中int参数表示一次性要获取几个许可,默认为1个,acquire方法在没有许可的情况下,要获取许可的线程会阻塞,而tryAcquire()方法在没有许可的情况下会立即返回 false,要获取许可的线程不会阻塞,这与Lock类的lock()与tryLock()类似
public void acquire()
//获取一个许可
public void acquire(int permits)
//获取permits个许可
public boolean tryAcquire()
//尝试获取一个许可,若获取成功,则立即返回true,若获取失败,则立即返回false
public boolean tryAcquire(long timeout, TimeUnit unit)
//尝试获取一个许可,若在指定的时间内获取成功,则立即返回true,否则则立即返回false
public boolean tryAcquire(int permits)
//尝试获取permits个许可,若获取成功,则立即返回true,若获取失败,则立即返回false
public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
//尝试获取permits个许可,若在指定的时间内获取成功,则立即返回true,否则则立即返回false
释放许可
线程可调用 release()、release(int)来释放(归还)许可,注意一个线程调用release()之前并不要求一定要调用了acquire (There is no requirement that a thread that releases a permit must have acquired that permit by calling {@link #acquire})
public void release()
//释放一个许可
public void release(int permits)
//释放permits个许可
例子:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class SemaPhoreTest {
public static void main(String[] args) {
// 线程池
ExecutorService exec = Executors.newCachedThreadPool();
// 只能5个线程同时访问
final Semaphore semp = new Semaphore(5);
// 模拟20个客户端访问
for (int index = 0; index < 50; index++) {
final int NO = index;
Runnable run = new Runnable() {
public void run() {
try {
// 获取许可
semp.acquire();
System.out.println("Accessing: " + NO);
Thread.sleep((long) (Math.random() * 6000));
// 访问完后,释放
semp.release();
//availablePermits()指的是当前信号灯库中有多少个可以被使用
System.out.println("-----------------" + semp.availablePermits());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
exec.execute(run);
}
// 退出线程池
exec.shutdown();
}
}
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.Semaphore;
public class SemaphoreTest {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(10); // 一共10个信号量
new Thread(new MyRunnable(semaphore,5), "线程1").start(); // 线程1 任务 需要 5个 信号量
new Thread(new MyRunnable(semaphore,3), "线程2").start(); // 线程2 任务 需要 3个 信号量
new Thread(new MyRunnable(semaphore,7), "线程3").start(); // 线程3 任务 需要 7个 信号量
}
}
class MyRunnable implements Runnable {
Semaphore semaphore;
int i;
public MyRunnable(Semaphore semaphore,int i){
this.semaphore = semaphore;
this.i = i;
}
@Override
public void run() {
try {
// 线程1,2,3运行到 semaphore.acquire(i)方法的时候,semaphore信号池的信号量是10
// 线程1和线程2分别获取了5个和3个信号量,线程池的限号量还剩2个
// 等线程3再去获取7个信号量的时候就会处于等待状态,
// 线程3只有等待线程1和线程2运行到 semaphore.release(i)时,线程3才能获取到足够的信号量,才能继续运行。
semaphore.acquire(i);
System.out.println(Thread.currentThread().getName()+", 获得 "+i+" 个信号量... do something");
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}finally {
// 释放给定数目的许可,将其返回到信号量。
semaphore.release(i);
System.out.println(Thread.currentThread().getName()+", 释放 "+i+" 个信号量");
}
}
}