-
CountDownLatch 是一个同步助手、允许一个或多个线程等待一系列其他线程的执行结束,在初始化CountDownLatch的时候,需要注意countDownLatch的特点
1:CountDownLatch ch=new CountDownLatch(5); 需要顶一个不小于0的计数器 2:CountDownLatch是同时并行多个程序,而不是并发 3:CountDownLatch是一次性的,不能重复使用 4:CountDownLatch在使用的时候,每个线程完成后需要对当前计数器减去1,countDown()需要在finally代码块中去完成,确保每个线程完成。
CountDownLatch用法示例一
package com.mxli.concurrent;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
final CountDownLatch ch=new CountDownLatch(5);
ExecutorService executorService= Executors.newFixedThreadPool(10);
for(int i=0;i<10;i++){
executorService.execute(new Runnable() {
@Override
public void run() {
try {
TimeUnit.MICROSECONDS.sleep(1000);
System.out.println("当前线程名称为1 :"+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
ch.countDown();//在finaly
}
}
});
}
ch.await();//调用await()方法后,主线程进入阻塞状态、等待所有计数器为0的时候,被唤醒
System.out.println("当前线程名称为2 :"+Thread.currentThread().getName());
}
}
当前线程名称为1 :pool-1-thread-8
当前线程名称为1 :pool-1-thread-1
当前线程名称为1 :pool-1-thread-5
当前线程名称为1 :pool-1-thread-4
当前线程名称为1 :pool-1-thread-6
当前线程名称为1 :pool-1-thread-9
当前线程名称为1 :pool-1-thread-10
当前线程名称为1 :pool-1-thread-7
当前线程名称为1 :pool-1-thread-3
当前线程名称为1 :pool-1-thread-2
当前线程名称为2 :main
在上边已经介绍,CountDownLatch是并行、
在CountDownlatch中、有一个比较频繁的面试题目、怎么让A,B,C三个线程顺序执行,一般除了join外,还可以使用CountDownlatch,代码如下
package com.mxli.concurrent;
public class CountDownLatchDemo1 {
public static void main(String[] args) throws InterruptedException {
Thread t1= new Thread(“A”){
@Override
public void run() {
System.out.println(“线程名称…”+Thread.currentThread().getName()+"-----1");
}
};
Thread t2= new Thread(“B”){
@Override
public void run() {
System.out.println(“线程名称…”+Thread.currentThread().getName()+"-----2");
}
};
Thread t3= new Thread(“C”){
@Override
public void run() {
System.out.println(“线程名称…”+Thread.currentThread().getName()+"-----3");
}
};
t1.start();
t1.join();
t2.start();
t2.join();
t3.start();
t3.join();
}
}
线程名称…A-----1
线程名称…B-----2
线程名称…C-----3
package com.mxli.concurrent;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class CountDownLatchDemo2 {
public static void main(String[] args) throws InterruptedException {
CountDownLatch c=new CountDownLatch(0);
CountDownLatch c1=new CountDownLatch(1);
CountDownLatch c2=new CountDownLatch(1);
Thread t1=new Thread(new Count(c,c1));
Thread t2=new Thread(new Count(c1,c2));
Thread t3=new Thread(new Count(c2,c2));
t1.start();
t2.start();
t3.start();
System.out.println(Thread.currentThread().getName());
}
static class Count implements Runnable{
CountDownLatch c;
CountDownLatch c1;
public Count(CountDownLatch c,CountDownLatch c1){
this.c=c;
this.c1=c1;
}
@Override
public void run() {
try {
c.await();
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
c1.countDown();
}
}
}
}
main
Thread-0
Thread-1
Thread-2
主要方法是await()会使当前调用线程进入阻塞、
countDown() 计数器-1,每次执行完一个线程、计算器减去1
- CyclicBarrier循环屏障
package com.mxli.concurrent;
import java.util.concurrent.*;
public class CyclicBarrierDemo {
public static void main(String[] args) throws BrokenBarrierException, InterruptedException, TimeoutException {
final CyclicBarrier c=new CyclicBarrier(5);
ExecutorService executorService= Executors.newFixedThreadPool(5);
for(int i=0;i<5;i++){
executorService.execute(new Runnable() {
@Override
public void run() {
try {
c.await();
TimeUnit.MICROSECONDS.sleep(100);
System.out.println(Thread.currentThread().getName()+"go");
c.await();
System.out.println(Thread.currentThread().getName()+"back");
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
});
}
System.out.println(Thread.currentThread().getName());
}
}
main
pool-1-thread-5go
pool-1-thread-1go
pool-1-thread-3go
pool-1-thread-2go
pool-1-thread-4go
pool-1-thread-4back
pool-1-thread-5back
pool-1-thread-3back
pool-1-thread-2back
pool-1-thread-1back
**c.await();** 第二次调用的时候
在重复调用await()方法的时候,当count为0,会生成新的eneration,这就是CyclicBarrier称为循环屏障的特点。
- Exchanger工具
交换器、两个线程的数据交互、两个线程互相调用exchange()方法、数据得到交换、如果只是想单纯的到一个线程的数据,另外一个参数可以设置为null
package com.mxli.concurrent;
import java.util.concurrent.Exchanger;
import java.util.concurrent.TimeUnit;
public class ExchangerDemo {
public static void main(String[] args) {
final Exchanger<String> exchanger=new Exchanger<>();
new Thread(){
@Override
public void run() {
try {
String msg=exchanger.exchange("美国佬爆炸了");
TimeUnit.MICROSECONDS.sleep(1000);
System.out.println(Thread.currentThread()+msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
new Thread(){
@Override
public void run() {
String msg= null;
try {
TimeUnit.MICROSECONDS.sleep(1000);
msg = exchanger.exchange("东风快递发射");
System.out.println(Thread.currentThread()+msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
Thread[Thread-1,5,main]美国佬爆炸了
Thread[Thread-0,5,main]东风快递发射
- Exchanger工具
Semaphore的作用:限制线程并发的数量
package com.mxli.concurrent;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class SemaphoreDemo {
public static void main(String[] args) {
final Semaphore c= new Semaphore(3);
ExecutorService executorService= Executors.newFixedThreadPool(10);
for(int i=0;i<10;i++){
executorService.execute(new Runnable() {
@Override
public void run() {
try {
c.acquire();//获取许可证
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(2);//
} catch (InterruptedException e) {
e.printStackTrace();
}
c.release();//释放许可证
}
});
}
}
}
pool-1-thread-2
pool-1-thread-3
pool-1-thread-1
pool-1-thread-4
pool-1-thread-6
pool-1-thread-5
pool-1-thread-7
pool-1-thread-10
pool-1-thread-8
pool-1-thread-9
每三个线程中间隔2S运行,
c.acquire();//获取许可证 获取许可证、
c.release();//释放许可证 每次只能进来三个线程去处理任务
通过以上例子可以看出,Semaphore 是一个限制线程的例子,那synchronized (),ReentrantLock()可以通过final Semaphore c= new Semaphore(1)控制、
常用方法解析
acquire() 方法是一个偏执狂,如果获取不到许可证就一直等待,属于死缠烂打的那种、除非获取到或者被其他线程中断、或者传入acquire(int) 类型、获取不到就等待或者被打断
tryacquire()尝试性获取,获取不到就返回false,
tryAcquire(long time,TimeUtil) 给定时间内获取许可证,获取不到就返回false
4. ReentrantLock()显示锁
package com.mxli.concurrent;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 10)
@Measurement(iterations = 10)
public class ReentrantLockDemo {
@State(Scope.Group)
public static class ReenTime{
private int x;
public void reemtime(){
Lock lock=new ReentrantLock();
lock.lock();
try {
x++;
}finally {
lock.unlock();
}
}
}
@State(Scope.Group)
public static class SynTime{
private int x;
public void syntime(){
synchronized (this){
x++;
}
}
}
@Benchmark
@Group("sync")
@GroupThreads(10)
public void synms(SynTime syn){
syn.syntime();
}
@Benchmark
@Group("reetn")
@GroupThreads(10)
public void reetn(ReenTime reenTime){
reenTime.reemtime();
}
public static void main(String[] args) throws RunnerException {
final Options opts=new OptionsBuilder().include(ReentrantLockDemo.class.getSimpleName())
.forks(1)
.warmupIterations(10)
.measurementIterations(10)
.build();
new Runner(opts).run();
}
}
Benchmark Mode Cnt Score Error Units
ReentrantLockDemo.reetn avgt 10 0.182 ± 0.001 us/op
ReentrantLockDemo.sync avgt 10 0.530 ± 0.011 us/op
JMH测试可得出,显示锁比synchronized ()执行效率要高,
在多线程进行数据读取的时候,读取不会造成数据不一致的情况、
读写锁分离的场景
private final ReadWriteLock readWriteLock=new ReentrantReadWriteLock();
private final Lock wirtelock=readWriteLock.writeLock();//创建写锁
private final Lock readlock=readWriteLock.readLock();//创建读锁
例子很多、不想写了。。。。
5. Condition
能够很好的替代wait(),notify(),notifuall(),Condition是由显示锁Lock创建的、一个显示锁可以关联多个Condition对象、