本文转载自微信公众号「潜行前行」,作者cscw 。转载本文请联系潜行前行公众号。

成都创新互联是一家专注于成都网站制作、做网站与策划设计,泾县网站建设哪家好?成都创新互联做网站,专注于网站建设十余年,网设计领域的专业建站公司;建站业务涵盖:泾县等地区。泾县做网站价格咨询:18982081108
前言
在使用多线程并发编程的时,经常会遇到对共享变量修改操作。此时我们可以选择ConcurrentHashMap,ConcurrentLinkedQueue来进行安全地存储数据。但如果单单是涉及状态的修改,线程执行顺序问题,使用Atomic开头的原子组件或者ReentrantLock、CyclicBarrier之类的同步组件,会是更好的选择,下面将一一介绍它们的原理和用法
原子组件的实现原理CAS
应用场景
原子组件
基本类型原子类
- AtomicBoolean //布尔类型
 - AtomicInteger //正整型数类型
 - AtomicLong //长整型类型
 
使用示例
- public static void main(String[] args) throws Exception {
 - AtomicBoolean atomicBoolean = new AtomicBoolean(false);
 - //异步线程修改atomicBoolean
 - CompletableFuture
 future = CompletableFuture.runAsync(() ->{ - try {
 - Thread.sleep(1000); //保证异步线程是在主线程之后修改atomicBoolean为false
 - atomicBoolean.set(false);
 - }catch (Exception e){
 - throw new RuntimeException(e);
 - }
 - });
 - atomicBoolean.set(true);
 - future.join();
 - System.out.println("boolean value is:"+atomicBoolean.get());
 - }
 - ---------------输出结果------------------
 - boolean value is:false
 
引用类原子类
- AtomicReference
 - //加时间戳版本的引用类原子类
 - AtomicStampedReference
 - //相当于AtomicStampedReference,AtomicMarkableReference关心的是
 - //变量是否还是原来变量,中间被修改过也无所谓
 - AtomicMarkableReference
 
- public class AtomicReference
 implements java.io.Serializable { - private static final long serialVersionUID = -1848883965231344442L;
 - private static final VarHandle VALUE;
 - static {
 - try {
 - MethodHandles.Lookup l = MethodHandles.lookup();
 - VALUE = l.findVarHandle(AtomicReference.class, "value", Object.class);
 - } catch (ReflectiveOperationException e) {
 - throw new ExceptionInInitializerError(e);
 - }
 - }
 - private volatile V value;
 - ....
 
ABA问题
- public class AtomicStampedReference
 { - private static class Pair
 { - final T reference;
 - final int stamp;
 - private Pair(T reference, int stamp) {
 - this.reference = reference;
 - this.stamp = stamp;
 - }
 - static
 Pair of(T reference, int stamp) { - return new Pair
 (reference, stamp); - }
 - }
 - private volatile Pair
 pair; 
- public class Main {
 - public static void main(String[] args) throws Exception {
 - Test old = new Test("hello"), newTest = new Test("world");
 - AtomicStampedReference
 reference = new AtomicStampedReference<>(old, 1); - reference.compareAndSet(old, newTest,1,2);
 - System.out.println("对象:"+reference.getReference().name+";版本号:"+reference.getStamp());
 - }
 - }
 - class Test{
 - Test(String name){ this.name = name; }
 - public String name;
 - }
 - ---------------输出结果------------------
 - 对象:world;版本号:2
 
数组原子类
- AtomicIntegerArray //整型数组
 - AtomicLongArray //长整型数组
 - AtomicReferenceArray //引用类型数组
 
- //元素默认初始化为0
 - AtomicIntegerArray array = new AtomicIntegerArray(2);
 - // 下标为0的元素,期待值是0,更新值是1
 - array.compareAndSet(0,0,1);
 - System.out.println(array.get(0));
 - ---------------输出结果------------------
 - 1
 
属性原子类
- AtomicIntegerFieldUpdater
 - AtomicLongFieldUpdater
 - AtomicReferenceFieldUpdater
 
- public class Main {
 - public static void main(String[] args) {
 - AtomicReferenceFieldUpdater
 fieldUpdater = AtomicReferenceFieldUpdater.newUpdater(Test.class,String.class,"name"); - Test test = new Test("hello world");
 - fieldUpdater.compareAndSet(test,"hello world","siting");
 - System.out.println(fieldUpdater.get(test));
 - System.out.println(test.name);
 - }
 - }
 - class Test{
 - Test(String name){ this.name = name; }
 - public volatile String name;
 - }
 - ---------------输出结果------------------
 - siting
 - siting
 
累加器
- Striped64
 - LongAccumulator
 - LongAdder
 - //accumulatorFunction:运算规则,identity:初始值
 - public LongAccumulator(LongBinaryOperator accumulatorFunction,long identity)
 
- public static void main(String[] args) throws Exception {
 - LongAccumulator accumulator = new LongAccumulator(Long::sum, 0);
 - for(int i=0;i<100000;i++){
 - CompletableFuture.runAsync(() -> accumulator.accumulate(1));
 - }
 - Thread.sleep(1000); //等待全部CompletableFuture线程执行完成,再获取
 - System.out.println(accumulator.get());
 - }
 - ---------------输出结果------------------
 - 100000
 
同步组件的实现原理
java的多数同步组件会在内部维护一个状态值,和原子组件一样,修改状态值时一般也是通过cas来实现。而状态修改的维护工作被Doug Lea抽象出AbstractQueuedSynchronizer(AQS)来实现
AQS的原理可以看下之前写的一篇文章:详解锁原理,synchronized、volatile+cas底层实现[2]
同步组件
ReentrantLock、ReentrantReadWriteLock
- ReentrantLock lock = new ReentrantLock();
 - if(lock.tryLock()){
 - //业务逻辑
 - lock.unlock();
 - }
 
- public static void main(String[] args) throws Exception {
 - ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
 - if(lock.readLock().tryLock()){ //读锁
 - //业务逻辑
 - lock.readLock().unlock();
 - }
 - if(lock.writeLock().tryLock()){ //写锁
 - //业务逻辑
 - lock.writeLock().unlock();
 - }
 - }
 
Semaphore实现原理和使用场景
- public static void main(String[] args) throws Exception {
 - Semaphore semaphore = new Semaphore(2);
 - for (int i = 0; i < 3; i++)
 - CompletableFuture.runAsync(() -> {
 - try {
 - System.out.println(Thread.currentThread().toString() + " start ");
 - if(semaphore.tryAcquire(1)){
 - Thread.sleep(1000);
 - semaphore.release(1);
 - System.out.println(Thread.currentThread().toString() + " 无阻塞结束 ");
 - }else {
 - System.out.println(Thread.currentThread().toString() + " 被阻塞结束 ");
 - }
 - } catch (Exception e) {
 - throw new RuntimeException(e);
 - }
 - });
 - //保证CompletableFuture 线程被执行,主线程再结束
 - Thread.sleep(2000);
 - }
 - ---------------输出结果------------------
 - Thread[ForkJoinPool.commonPool-worker-19,5,main] start
 - Thread[ForkJoinPool.commonPool-worker-5,5,main] start
 - Thread[ForkJoinPool.commonPool-worker-23,5,main] start
 - Thread[ForkJoinPool.commonPool-worker-23,5,main] 被阻塞结束
 - Thread[ForkJoinPool.commonPool-worker-5,5,main] 无阻塞结束
 - Thread[ForkJoinPool.commonPool-worker-19,5,main] 无阻塞结束
 
可以看出三个线程,因为信号量设定为2,第三个线程是无法获取信息成功的,会打印阻塞结束
CountDownLatch实现原理和使用场景
- public static void main(String[] args) throws Exception {
 - CountDownLatch count = new CountDownLatch(2);
 - for (int i = 0; i < 2; i++)
 - CompletableFuture.runAsync(() -> {
 - try {
 - Thread.sleep(1000);
 - System.out.println(" CompletableFuture over ");
 - count.countDown();
 - } catch (Exception e) {
 - throw new RuntimeException(e);
 - }
 - });
 - //等待CompletableFuture线程的完成
 - count.await();
 - System.out.println(" main over ");
 - }
 - ---------------输出结果------------------
 - CompletableFuture over
 - CompletableFuture over
 - main over
 
CyclicBarrier实现原理和使用场景
- public static void main(String[] args) throws Exception {
 - CyclicBarrier barrier = new CyclicBarrier(2);
 - CompletableFuture.runAsync(()->{
 - try {
 - System.out.println("CompletableFuture run start-"+ Clock.systemUTC().millis());
 - barrier.await(); //需要等待main线程也执行到await状态才能继续执行
 - System.out.println("CompletableFuture run over-"+ Clock.systemUTC().millis());
 - }catch (Exception e){
 - throw new RuntimeException(e);
 - }
 - });
 - Thread.sleep(1000);
 - //和CompletableFuture线程相互等待
 - barrier.await();
 - System.out.println("main run over!");
 - }
 - ---------------输出结果------------------
 - CompletableFuture run start-1609822588881
 - main run over!
 - CompletableFuture run over-1609822589880
 
StampedLock
- //获取读锁,自旋获取,返回一个戳值
 - public long readLock()
 - //尝试加读锁,不成功返回0
 - public long tryReadLock()
 - //解锁
 - public void unlockRead(long stamp)
 - //获取写锁,自旋获取,返回一个戳值
 - public long writeLock()
 - //尝试加写锁,不成功返回0
 - public long tryWriteLock()
 - //解锁
 - public void unlockWrite(long stamp)
 - //尝试乐观读读取一个时间戳,并配合validate方法校验时间戳的有效性
 - public long tryOptimisticRead()
 - //验证stamp是否有效
 - public boolean validate(long stamp)
 
- public static void main(String[] args) throws Exception {
 - StampedLock stampedLock = new StampedLock();
 - long stamp = stampedLock.tryOptimisticRead();
 - //判断版本号是否生效
 - if (!stampedLock.validate(stamp)) {
 - //获取读锁,会空转
 - stamp = stampedLock.readLock();
 - long writeStamp = stampedLock.tryConvertToWriteLock(stamp);
 - if (writeStamp != 0) { //成功转为写锁
 - //fixme 业务操作
 - stampedLock.unlockWrite(writeStamp);
 - } else {
 - stampedLock.unlockRead(stamp);
 - //尝试获取写读
 - stamp = stampedLock.tryWriteLock();
 - if (stamp != 0) {
 - //fixme 业务操作
 - stampedLock.unlockWrite(writeStamp);
 - }
 - }
 - }
 - }
 
参考文章
参考资料
[1]详解锁原理,synchronized、volatile+cas底层实现: https://juejin.cn/post/6854573210768900110
[2]详解锁原理,synchronized、volatile+cas底层实现: https://juejin.cn/post/6854573210768900110
[3]并发之Striped64(l累加器): https://www.cnblogs.com/gosaint/p/9129867.html
                当前名称:基础篇:Java原子组件和同步组件
                
                文章网址:http://www.csdahua.cn/qtweb/news34/405434.html
            
网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网