JAVA高并发之并发包工具类

  1. 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

  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称为循环屏障的特点。

  1. 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]东风快递发射
  1. 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对象、

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值