并发工具类

1.Exchanger  

方法摘要:

 Vexchange(V x)
          等待另一个线程到达此交换点(除非当前线程被中断),然后将给定的对象传送给该线程,并接收该线程的对象。
 Vexchange(V x, long timeout, TimeUnit unit)
          等待另一个线程到达此交换点(除非当前线程被中断,或者超出了指定的等待时间),然后将给定的对象传送给该线程,同时接收该线程的对象。

功能:用于线程间数据的交换

应用场景:1)遗传算法,目前还不是特别理解  2)校对工作,假设A,B线程做同一件任务,可以通过数据校验判断两线程是否正确的工作

private java.util.concurrent.Exchanger<String> exchanger;
private String userName;
private String phone;
public ExchangerTest(Exchanger<String> exchanger, String userName, String phone){
this.exchanger=exchanger;
this.userName=userName;
this.phone=phone;
}

@Override
public void run() {
try {
System.out.println(exchanger.exchange(userName)+":"+phone);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

public static void main(String[] args) {
Exchanger<String> exchanger=new Exchanger<>();
ExchangerTest exchangerTest=new ExchangerTest(exchanger,"你的姓名","0101");
ExchangerTest exchangerTest2=new ExchangerTest(exchanger,"你的代号","ming");
new Thread(exchangerTest).start();
new Thread(exchangerTest2).start();
}

2.Semaphore

 voidacquire()
          从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。
 voidacquire(int permits)
          从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞,或者线程已被中断。
 voidacquireUninterruptibly()
          从此信号量中获取许可,在有可用的许可前将其阻塞。
 voidacquireUninterruptibly(int permits)
          从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞。
 intavailablePermits()
          返回此信号量中当前可用的许可数。
 intdrainPermits()
          获取并返回立即可用的所有许可。
protected  Collection<Thread>getQueuedThreads()
          返回一个 collection,包含可能等待获取的线程。
 intgetQueueLength()
          返回正在等待获取的线程的估计数目。
 booleanhasQueuedThreads()
          查询是否有线程正在等待获取。
 booleanisFair()
          如果此信号量的公平设置为 true,则返回 true
protected  voidreducePermits(int reduction)
          根据指定的缩减量减小可用许可的数目。
 voidrelease()
          释放一个许可,将其返回给信号量。
 voidrelease(int permits)
          释放给定数目的许可,将其返回到信号量。
 StringtoString()
          返回标识此信号量的字符串,以及信号量的状态。
 booleantryAcquire()
          仅在调用时此信号量存在一个可用许可,才从信号量获取许可。
 booleantryAcquire(int permits)
          仅在调用时此信号量中有给定数目的许可时,才从此信号量中获取这些许可。
 booleantryAcquire(int permits, long timeout, TimeUnit unit)
          如果在给定的等待时间内此信号量有可用的所有许可,并且当前线程未被中断,则从此信号量获取给定数目的许可。
 booleantryAcquire(long timeout, TimeUnit unit)
          如果在给定的等待时间内,此信号量有可用的许可并且当前线程未被中断,则从此信号量获取一个许可。

功能:控制同时访问特定资源的线程数量

应用场景:流量控制,比如数据库的连接

Semaphore主要方法:

Semaphore(int permits):构造方法,创建具有给定许可数的计数信号量并设置为非公平信号量。

Semaphore(int permits,boolean fair):构造方法,当fair等于true时,创建具有给定许可数的计数信号量并设置为公平信号量。

void acquire():从此信号量获取一个许可前线程将一直阻塞。相当于一辆车占了一个车位。

void acquire(int n):从此信号量获取给定数目许可,在提供这些许可前一直将线程阻塞。比如n=2,就相当于一辆车占了两个车位。

void release():释放一个许可,将其返回给信号量。就如同车开走返回一个车位。

void release(int n):释放n个许可。

int availablePermits():当前可用的许可数。

序号名称类型含义
1corePoolSizeint核心线程池大小
2maximumPoolSizeint最大线程池大小
3keepAliveTimelong线程最大空闲时间
4unitTimeUnit时间单位
5workQueueBlockingQueue<Runnable>线程等待队列
6threadFactoryThreadFactory线程创建工厂
7handlerRejectedExecutionHandler拒绝策略
  含义:
就是在该类初始化的时候,给定一个数字A,每个线程调用acquire()方法后,
首先判断A是否大于0,如果大于0,就将A减去1,然后执行对应的线程,如果不大于0,那么就会阻塞,
直到其他线程调用了release()方法,将A加上1,该线程可能有执行的机会.
场景介绍:
  有一个停车场只有5个车位,现在有100辆车要去抢这个5个车位,
理想情况下最多只有五辆车同时可以抢到车位,那么没有抢到车位的车只能等到,其他的车让出车位,才有机会去使用该车位。
public static void main(String[] args) {
//阻塞队列
BlockingQueue<String> parks = new LinkedBlockingQueue<>(5);

parks.offer("车位一");
parks.offer("车位二");
parks.offer("车位三");
parks.offer("车位四");
parks.offer("车位五");

ExecutorService executorService = Executors.newCachedThreadPool();

//如博文中所说的初始值为5, 专业的说法就是5个许可证
Semaphore semaphore = new Semaphore(2);

for (int i = 0; i < 100; i++) {
final int no = i;
Thread t1 = new Thread(() -> {
try {
/**
* 获取许可,首先判断semaphore内部的数字是否大于0,如果大于0,
* 才能获得许可,然后将初始值5减去1,线程才会接着去执行;如果没有
* 获得许可(原因是因为已经有5个线程获得到许可,semaphore内部的数字为0),
* 线程会阻塞直到已经获得到许可的线程,调用release()方法,释放掉许可,
* 也就是将semaphore内部的数字加1,该线程才有可能获得许可。
*/
semaphore.acquire();
/**
* 对应的线程会到阻塞对,对应车辆去获取到车位,如果没有拿到一致阻塞,
* 直到其他车辆归还车位。
*/
String park = parks.take();
System.out.println("车辆【" + no + "】获取到: " + park);
Thread.sleep((long) Math.random() * 6000);
semaphore.release(); //线程释放掉许可,通俗来将就是将semaphore内部的数字加1
parks.offer(park); //归还车位
System.out.println("车辆【" + no + "】离开 " + park);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
executorService.execute(t1);
}
}

3.CyclicBarrier

 intawait()
          在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。
 intawait(long timeout, TimeUnit unit)
          在所有参与者都已经在此屏障上调用 await 方法之前将一直等待,或者超出了指定的等待时间。
 intgetNumberWaiting()
          返回当前在屏障处等待的参与者数目。
 intgetParties()
          返回要求启动此 barrier 的参与者数目。
 booleanisBroken()
          查询此屏障是否处于损坏状态。
 voidreset()
          将屏障重置为其初始状态。

功能:控制同时访问特定资源的线程数量

应用场景:希望创建一组任务,并行执行,在进行下一个步骤之前等待,直到所有任务完成

  static class TaskThread extends  Thread{
CyclicBarrier cyclicBarrier;
public TaskThread(CyclicBarrier cyclicBarrier){
this.cyclicBarrier=cyclicBarrier;
}
@Override
public void run() {
try {
Thread.sleep(1000);
System.out.println(getName()+"到达栅栏 A");
cyclicBarrier.await();
System.out.println(getName()+"冲破栅栏 A");
Thread.sleep(1000);
System.out.println(getName()+"到达栅栏 B");
cyclicBarrier.await();
System.out.println(getName()+"冲破栅栏 B");
} catch (InterruptedException e) {
e.printStackTrace();
}catch (BrokenBarrierException e) {
e.printStackTrace();
}
}

public static void main(String[] args) {
int number=3;
CyclicBarrier cyclicBarrier1=new CyclicBarrier(number, new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"完成最后任务");
}
});
for (int i = 0; i <number; i++) {
new TaskThread(cyclicBarrier1).start();
}
}
}

4. CyclicBarrier 与 CountDownLatch 区别

  • CountDownLatch 是一次性的,CyclicBarrier 是可循环利用的
  • CountDownLatch 参与的线程的职责是不一样的,有的在倒计时,有的在等待倒计时结束。CyclicBarrier 参与的线程职责是一样的。
  • 
    

4.CountDownLatch

方法区: 

 voidawait()
          使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断。
 booleanawait(long timeout, TimeUnit unit)
          使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。
 voidcountDown()
          递减锁存器的计数,如果计数到达零,则释放所有等待的线程。
 longgetCount()
          返回当前计数。
 StringtoString()
          返回标识此锁存器及其状态的字符串。
CountDownLatch(int count) //实例化一个倒计数器,count指定计数个数
countDown() // 计数减一
await() //等待,当计数减到0时,所有线程并行执行

功能:允许一个或多个线程等待其他线程完成操作

  • static final CountDownLatch countdownLatch=new CountDownLatch(10);
    static final CountDownLatchTest countDownLatchTest=new CountDownLatchTest();
  • @Override
    public void run() {
    try {
    Thread.sleep(new Random().nextInt(10)*6000);
    System.out.println("开始检查发射配置");
    } catch (InterruptedException e) {
    e.printStackTrace();
    }finally {
    countdownLatch.countDown();//加一操作
    }
    }
    public static void main(String[] args) throws InterruptedException {
    ExecutorService executorService=Executors.newFixedThreadPool(10);
    for (int i = 0; i <10 ; i++) {
    executorService.submit(countDownLatchTest);
    }
    countdownLatch.await();//等待全部完成
    System.out.println("火箭发射");
    executorService.shutdown();//关闭线程
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知青先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值