IT评测·应用市场-qidao123.com

标题: 04、JUC并发编程之:简单概述(四) [打印本页]

作者: 慢吞云雾缓吐愁    时间: 2025-1-1 23:38
标题: 04、JUC并发编程之:简单概述(四)
JUC并发编程之:简单概述(四)

  1. ##本章内容:
  2. 无锁并发--乐观锁(非阻塞)
  3. ·CAS与volatile
  4. ·原子整数
  5. ·原子引用
  6. ·原子数组
  7. ·字段更新器
  8. ·原子累加器
  9. ·Unsafe
复制代码
一、CAS与volatile

1、掩护共享资源

  1. ·有一个账户,有1万元,现在有1000个线程,每个线程每次取10元,最后会剩下0元
  2. ##错误实现 与  加锁实现
复制代码
  1. @Slf4j
  2. public class CasAndVolatile01 {
  3.     public static void main(String[] args) {
  4.         //unsafe实现
  5.         Account account1 = new AccountUnsafe(10000);
  6.         Account.demo(account1);
  7.         //加锁实现
  8.         Account account2 = new AccountLock(10000);
  9.         Account.demo(account2);
  10.     }
  11. }
  12. //加锁实现
  13. class AccountLock implements Account{
  14.     Integer balance;
  15.     public AccountLock(Integer balance) {
  16.         this.balance = balance;
  17.     }
  18.     @Override
  19.     public Integer getBalance() {
  20.         synchronized (this){
  21.             return this.balance;
  22.         }
  23.     }
  24.     @Override
  25.     public void withDraw(Integer amount) {
  26.         synchronized (this){
  27.             this.balance -= amount;
  28.         }
  29.     }
  30. }
  31. //错误实现
  32. class AccountUnsafe implements Account{
  33.     Integer balance;
  34.     public AccountUnsafe(Integer balance) {
  35.         this.balance = balance;
  36.     }
  37.     @Override
  38.     public Integer getBalance() {
  39.         return this.balance;
  40.     }
  41.     @Override
  42.     public void withDraw(Integer amount) {
  43.         this.balance -= amount;
  44.     }
  45. }
  46. interface Account{
  47.     //获取余额
  48.     Integer getBalance();
  49.     //取款
  50.     void withDraw(Integer amount);
  51.     //方法内启动1000个线程,每个线程-10元
  52.     //如果总额为10000,那么余额将会为0
  53.     static void demo(Account account){
  54.         List<Thread> ts = new ArrayList<>();
  55.         for(int i=0;i<1000;i++){
  56.             ts.add(new Thread(()->{
  57.                 account.withDraw(10);
  58.             }));
  59.         }
  60.         //计算起始时间
  61.         long start = System.nanoTime();
  62.         ts.forEach(Thread::start);
  63.         ts.forEach(t->{
  64.             try {
  65.                 t.join();
  66.             } catch (InterruptedException e) {
  67.                 e.printStackTrace();
  68.             }
  69.         });
  70.         long end = System.nanoTime();
  71.         System.out.println(account.getBalance()
  72.         +"  cost : "+(end-start)/1000_000+"ms");
  73.     }
  74. }
复制代码
  1. ##结果:
  2. 310  cost : 80ms  ##错误实现
  3. 0  cost : 69ms  ##加锁实现
  4. ##无锁实现
复制代码
  1. //无锁实现
  2. class AccountCas implements Account{
  3.     AtomicInteger balance;
  4.     public AccountCas(Integer balance) {
  5.         this.balance = new AtomicInteger(balance);
  6.     }
  7.     @Override
  8.     public Integer getBalance() {
  9.         return balance.get(); //底层是volatile
  10.     }
  11.     @Override
  12.     public void withDraw(Integer amount) {
  13.         while(true){
  14.             //余额最新值
  15.             Integer prev = balance.get();
  16.             //修改后的余额
  17.             Integer next = prev - amount;
  18.             //同步到主存--比较并设置
  19.             if(balance.compareAndSet(prev,next)){
  20.                 break;
  21.             }
  22.         }
  23.     }
  24. }
复制代码
  1. ##结果:
  2. 160  cost : 85ms ##错误实现
  3. 0  cost : 73ms   ##加锁实现
  4. 0  cost : 65ms   ##无锁实现
复制代码
2、CAS与volatile

CAS:
  1. ·上面AtomicInteger的解决方法,内部并没有使用锁来保护共享变量的线程安全,它的实现原理:
  2. @Override
  3. public void withDraw(Integer amount) {
  4.     while(true){
  5.         //余额最新值
  6.         Integer prev = balance.get();
  7.         //修改后的余额
  8.         Integer next = prev - amount;
  9.         //同步到主存---比较并设置
  10.         if(balance.compareAndSet(prev,next)){
  11.                 break;
  12.         }
  13.     }
  14. }
  15. 其中compareAndSet,它的简称就是CAS(也称 compare and swap),它必须是原子操作
复制代码

  1. ·CAS底层是lock cmpxchg指令(X86架构),在单个CPU和多核CPU下都能够保证【比较-交换】的原子
  2. ·在多核状态下,某个执行到带lock的指令时,CPU会让总线锁住,当这个核把此指令执行完毕,再开启
  3. 总线,这个过程中不会被线程的调度机制所打断,保证了多个线程对内存操作的准确性,是原子的。
  4. 【CAS会在修改前判断 自己共享变量修改之前读到的数据和当前的数据是否一致,如果不一致则返回
  5. ·false,重新修改,如果一致则返回true修改成功】
复制代码
volatile:
  1. ·获取共享变量时,为了保证该变量的可见性,需要使用volatile修饰。
  2. ·它可以用来修饰成员变量和静态成员变量,它可以避免线程从自己的工作缓存中查找变量的值,必须到
  3. 主存中获取他的值,线程操作volatile变量都是直接操作主存。即一个线程对volatile变量的修改,
  4. 对另一个线程可见。
  5. ##注意:
  6. volatile仅保证了共享变量的可见性,让其他线程能够看到最新值,但不能解决指令交错问题
  7. (不能保证原子性)
  8. ·【CAS必须借助volatile才能读取到共享变量的最新值来实现【比较并交换】的效果】
  9. ##AtomicInteger部分源码:
  10. public class AtomicInteger{
  11.   private volatile int value;
  12. }
复制代码
3、CAS效率分析

  1. ##为什么无锁效率高?
  2. ·无锁情况下,即使重试失败,线程始终在高速运行,没有停歇,而synchronized会让线程在没有获得
  3. 锁的时候,发生上下文切换,进入阻塞
  4. (打个比方:线程就好像高速跑道上的赛车,高速运行时,速度超快,一旦发生上下文切换,就好比赛车减
  5. 速,熄火,等被唤醒又得重新打火、启动、加速恢复到高速运行,代价比较大)
  6. ·但无锁情况下因为线程要保持运行,需要额外CPU的支持,CPU在这里就好比高速跑道,没有额外的跑
  7. 道,线程想高速运行也无从谈起,虽然不会进入阻塞,但由于没有分到时间片,仍然会进入可运行状态,
  8. 还是会导致上下文切换。
复制代码
4、CAS特点

  1. ·CAS结合volatile可以实现无锁并发,适用于线程数少,多核CPU的场景下:
  2. >CAS是基于乐观锁的思想:最乐观的估计,不怕别的线程来修改共享变量,就算改了也没关系,我吃点亏
  3. 再重试呗
  4. >synchronized是基于悲观锁的思想:最悲观的估计,得防着其他线程来修改共享变量,我上了锁你们
  5. 都别想改,我改完了解开锁,你们才有机会
  6. >CAS体现的是无锁并发,无阻塞并发:
  7.   >>因为没有使用synchronized,所以县城不会陷入阻塞,这是效率提升的因素之一
  8.   >>但如果竞争激烈,可以想到重试必然发生,反而会影响效率
复制代码
二、原子整数

  1. ##JUC并发包提供了一些供CAS实现工具类:
  2. ·AtomicBoolean
  3. ·AtomicInteger
  4. ·AtomicLong
  5. ##ActomicInteger常用方法:
复制代码
  1. @Slf4j
  2. public class ActomicIntegerTest {
  3.     public static void main(String[] args) {
  4.         AtomicInteger i = new AtomicInteger(0);
  5.         System.out.println(i.incrementAndGet());//++i
  6.         System.out.println(i.getAndIncrement());//i++
  7.         System.out.println(i.addAndGet(5));//先+5然后get
  8.         System.out.println(i.getAndAdd(5));//先get然后+5
  9.         System.out.println(i.updateAndGet(x->x*5));//先乘以5后get
  10.         System.out.println(i.getAndUpdate(x->x*5));//先get然后乘以5
  11.         System.out.println(i.get());
  12.     }
  13. }
复制代码
updateAndGet( )底层源码:
  1. public final int updateAndGet(IntUnaryOperator updateFunction) {
  2.     int prev, next;
  3.     do {
  4.         prev = get();
  5.         next = updateFunction.applyAsInt(prev);
  6.     } while (!compareAndSet(prev, next));
  7.     return next;
  8. }
复制代码
三、原子引用

  1. ##由于我们的共享变量并不一定都是基本数据类型,比如说BigDecimal,我们就可以使用原子引用
  2. 保证该共享变量的线程安全
  3. ·AtomicReference
  4. ·AtomicMarkableReference
  5. ·AtomicStampedReference  有版本号的
复制代码
3.1、AtomicReference

  1. public class CasAndVolatile02 {
  2.     public static void main(String[] args) {
  3.         DecimalAccount account = new BigDecimalAccountCas(new BigDecimal("10000"));
  4.         DecimalAccount.demo(account);
  5.     }
  6. }
  7. class BigDecimalAccountCas implements DecimalAccount{
  8.     private AtomicReference<BigDecimal> balance;
  9.     public BigDecimalAccountCas(BigDecimal balance) {
  10.         this.balance = new AtomicReference<>(balance);
  11.     }
  12.     @Override
  13.     public BigDecimal getBalance() {
  14.         return balance.get();
  15.     }
  16.     @Override
  17.     public void withDraw(BigDecimal amount) {
  18.         while (true){
  19.             BigDecimal prev = balance.get();
  20.             BigDecimal next = prev.subtract(amount);
  21.             if(balance.compareAndSet(prev,next)){
  22.                 break;
  23.             }
  24.         }
  25.     }
  26. }
  27. interface DecimalAccount{
  28.     //获取余额
  29.     BigDecimal getBalance();
  30.     //取款
  31.     void withDraw(BigDecimal amount);
  32.     //方法内启动1000个线程,每个线程-10元
  33.     //如果总额为10000,那么余额将会为0
  34.     static void demo(DecimalAccount account2){
  35.         List<Thread> ts = new ArrayList<>();
  36.         for(int i=0;i<1000;i++){
  37.             ts.add(new Thread(()->{
  38.                 account2.withDraw(BigDecimal.TEN);
  39.             }));
  40.         }
  41.         //计算起始时间
  42.         long start = System.nanoTime();
  43.         ts.forEach(Thread::start);
  44.         ts.forEach(t->{
  45.             try {
  46.                 t.join();
  47.             } catch (InterruptedException e) {
  48.                 e.printStackTrace();
  49.             }
  50.         });
  51.         long end = System.nanoTime();
  52.         System.out.println(account2.getBalance()
  53.                 +"  cost : "+(end-start)/1000_000+"ms");
  54.     }
  55. }
复制代码
3.2、ABA问题:

  1. ##主线程将共享变量从A---修改成---->C
  2. ##但在主线程修改过程中t线程将共享变量从A---修改成---->B---又修改成--->A
  3. ##主线程还是会修改成功,但主线程是无法感知共享变量的变化的
  4. ##代码如下:
复制代码
  1. @Slf4j
  2. public class AtomicReferenceABA01 {
  3.     static AtomicReference<String> at = new AtomicReference("A");
  4.     public static void main(String[] args) {
  5.         log.debug("main start...");
  6.         String prev = at.get();
  7.         other();
  8.         try {
  9.             Thread.sleep(1000);
  10.         } catch (InterruptedException e) {
  11.             e.printStackTrace();
  12.         }
  13.         log.debug("main change A-->C : {}",at.compareAndSet(prev,"C"));
  14.     }
  15.     private static void other(){
  16.         new Thread(()->{
  17.             log.debug("t1 change A-->B : {}",at.compareAndSet("A","B"));
  18.         },"t1").start();
  19.         try {
  20.             Thread.sleep(500);
  21.         } catch (InterruptedException e) {
  22.             e.printStackTrace();
  23.         }
  24.         new Thread(()->{
  25.             log.debug("t1 change B-->A : {}",at.compareAndSet("B","A"));
  26.         },"t2").start();
  27.     }
  28. }
复制代码
  1. ##结果:
  2. 10:06:54.024 [main] DEBUG xxx - main start...
  3. 10:06:54.119 [t1] DEBUG xxx - t1 change A-->B : true
  4. 10:06:54.620 [t2] DEBUG xxx - t1 change B-->A : true
  5. 10:06:55.634 [main] DEBUG xxx - main change A-->C : true
  6. ##如何才能让main线程感知到 共享变量被修改呢?
  7. ##只要有其他线程动过了共享变量,那么自己的CAS就算失败,这时仅比较值是不够的,
  8. 需要再增加一个版本号
复制代码
3.3、AtomicStampedReference

  1. @Slf4j
  2. public class AtomicStampedReferenceABA02 {
  3.     static AtomicStampedReference<String> asr =new AtomicStampedReference<>("A",0);
  4.     public static void main(String[] args) {
  5.         log.debug("main start....");
  6.         String prev = asr.getReference();
  7.         int stamp = asr.getStamp();
  8.         log.debug("main prev:{} , stamp:{}",prev,stamp);
  9.         other();
  10.         try {
  11.             Thread.sleep(1000);
  12.         } catch (InterruptedException e) {
  13.             e.printStackTrace();
  14.         }
  15.         log.debug("main change A-->C : {}",asr.compareAndSet(prev,"C",stamp,stamp+1));
  16.     }
  17.     private static void other(){
  18.         new Thread(()->{
  19.             String prev = asr.getReference();
  20.             int stamp = asr.getStamp();
  21.             log.debug("t1 prev:{} , stamp:{}",prev,stamp);
  22.             log.debug("t1 change A-->B : {}",asr.compareAndSet(prev,"B",stamp,stamp+1));
  23.         },"t1").start();
  24.         try {
  25.             Thread.sleep(1000);
  26.         } catch (InterruptedException e) {
  27.             e.printStackTrace();
  28.         }
  29.         new Thread(()->{
  30.             String prev = asr.getReference();
  31.             int stamp = asr.getStamp();
  32.             log.debug("t2 prev:{} , stamp:{}",prev,stamp);
  33.             log.debug("t2 change B-->A : {}",asr.compareAndSet(prev,"A",stamp,stamp+1));
  34.         },"t2").start();
  35.     }
  36. }
复制代码
  1. ##结果:
  2. 10:25:43.158 [main] DEBUG xxx - main start....
  3. 10:25:43.172 [main] DEBUG xxx - main prev:A , stamp:0
  4. 10:25:43.217 [t1] DEBUG xxx - t1 prev:A , stamp:0
  5. 10:25:43.217 [t1] DEBUG xxx - t1 change A-->B : true
  6. 10:25:44.227 [t2] DEBUG xxx - t2 prev:B , stamp:1
  7. 10:25:44.227 [t2] DEBUG xxx - t2 change B-->A : true
  8. 10:25:45.242 [main] DEBUG xxx - main change A-->C : false
复制代码
3.4、AtomicMarkableReference

  1. ##AtomicStampedReference 通过版本号 可以记录 是否被修改了,和修改了几次
  2. ##AtomicMarkableReference 通过boolean标记 是否被修改
复制代码
  1. @Slf4j
  2. public class AtomicMarkableReferenceTest {
  3.     public static void main(String[] args) {
  4.         GarbageBag bag = new GarbageBag("一个满了的垃圾袋");
  5.         AtomicMarkableReference<GarbageBag> amr = new AtomicMarkableReference<>(bag,true);
  6.         log.debug("main start...");
  7.         GarbageBag prev = amr.getReference();
  8.         log.debug("main prev:{}",prev);
  9.         new Thread(()->{
  10.             log.debug("清洁阿姨 更换垃圾袋: {}",amr.compareAndSet(prev,new GarbageBag("清洁阿姨放了一个新的垃圾袋"),true,false));
  11.         },"清洁阿姨").start();
  12.         try {
  13.             Thread.sleep(1000);
  14.         } catch (InterruptedException e) {
  15.             e.printStackTrace();
  16.         }
  17.         log.debug("main 更换垃圾袋: {}",amr.compareAndSet(prev,new GarbageBag("main放了一个新的垃圾袋"),true,false));
  18.     }
  19. }
  20. @Data
  21. @ToString
  22. @AllArgsConstructor
  23. class GarbageBag{
  24.     private String desc;
  25. }
复制代码
  1. ##结果:
  2. 10:41:53.070 [main] DEBUG xxx - main start...
  3. 10:41:53.086 [main] DEBUG xxx - main prev:GarbageBag(desc=一个满了的垃圾袋)
  4. 10:41:53.150 [清洁阿姨] DEBUG xxx - 清洁阿姨 更换垃圾袋: true
  5. 10:41:54.149 [main] DEBUG xxx - main 更换垃圾袋: false
复制代码
四、原子数组

  1. ·AtomicIntegerArray
  2. ·AtomicLongArray
  3. ·AtomicReferenceArray
  4. ##原子数组可以在多线程中保护数组里的元素
复制代码
  1. @Slf4j
  2. public class AtomicIntegerArrayTest {
  3.     public static void main(String[] args) {
  4.         //创建了容量为10个int的AtomicIntegerArray
  5.         AtomicIntegerArray array = new AtomicIntegerArray(10);
  6.         log.debug("第2个值:{}",array.get(1));
  7.         int[] array2 = new int[]{1,2,3,4,5,6,7,8,9,10};
  8.         AtomicIntegerArray array3 = new AtomicIntegerArray(array2);
  9.         log.debug("第2个值:{}",array3.get(1));
  10.         log.debug("第2个值+1:{}",array3.getAndIncrement(1));
  11.         log.debug("第2个值:{}",array3.get(1));
  12.         log.debug("第3个值+5:{}",array3.getAndAdd(2,5));
  13.         log.debug("第3个值:{}",array3.get(2));
  14.         log.debug("第4个值*7:{}",array3.getAndUpdate(3,t->t*7));
  15.         log.debug("第3个值:{}",array3.get(3));
  16.         
  17.         log.debug("修改第5个值为999");
  18.         array3.set(4,999);
  19.         log.debug("第5个值:{}",array3.get(4));
  20.     }
  21. }
复制代码
  1. ##结果:
  2. 11:45:37.301 [main] DEBUG xxx - 第2个值:0
  3. 11:45:37.316 [main] DEBUG xxx - 第2个值:2
  4. 11:45:37.317 [main] DEBUG xxx - 第2个值+1:2
  5. 11:45:37.317 [main] DEBUG xxx - 第2个值:3
  6. 11:45:37.317 [main] DEBUG xxx - 第3个值+5:3
  7. 11:45:37.317 [main] DEBUG xxx - 第3个值:8
  8. 11:45:37.361 [main] DEBUG xxx - 第4个值*7:4
  9. 11:45:37.361 [main] DEBUG xxx - 第3个值:28
  10. 11:47:45.114 [main] DEBUG xxx - 修改第5个值为999
  11. 11:47:45.114 [main] DEBUG xxx - 第5个值:999
复制代码
五、字段更新器

  1. ·AtomicReferenceFieldUpdater
  2. ·AtomicIntegerFieldUpdater
  3. ·AtomicLongFieldUpdater
  4. ##字段更新器可以在多线程中保护对象的某个属性\成员变量
复制代码
  1. @Slf4j
  2. public class AtomicReferenceFieldUpdaterTest {
  3.     public static void main(String[] args) {
  4.         Student st = new Student("李四");
  5.         //参数:类,要更新字段的类型,要更新字段的名称
  6.         AtomicReferenceFieldUpdater updater = AtomicReferenceFieldUpdater.newUpdater(Student.class,String.class,"name");
  7.         log.debug("更新名称为张三:{}",updater.compareAndSet(st,"李四","张三"));
  8.         log.debug("st : {}",st);
  9.     }
  10. }
  11. @Data
  12. @ToString
  13. @AllArgsConstructor
  14. class Student{
  15.     volatile String name;
  16. }
复制代码
六、原子累加器

  1. ##ActomicLong和LongAdder累加的性能比较
复制代码
  1. @Slf4j
  2. public class LongAdderTest {
  3.     public static void main(String[] args) {
  4.         for (int i = 0; i <5 ; i++) {
  5.             demo(
  6.                     ()->new AtomicLong(0),
  7.                     (adder)->adder.getAndIncrement()
  8.             );
  9.         }
  10.         log.debug("-------------");
  11.         for (int i = 0; i <5 ; i++) {
  12.             demo(
  13.                     ()->new LongAdder(),
  14.                     (adder)->adder.increment()
  15.             );
  16.         }
  17.     }
  18.     private static <T> void demo(Supplier<T> supplier, Consumer<T> consumer){
  19.         T adder = supplier.get();
  20.         List<Thread> ts = new ArrayList<>();
  21.         //4个线程,每人累加50万
  22.         for (int i=0;i<4;i++){
  23.            ts.add( new Thread(()->{
  24.                 for(int j=0;j<500000;j++){
  25.                     consumer.accept(adder);
  26.                 }
  27.            }));
  28.         }
  29.         long start = System.nanoTime();
  30.         ts.forEach(t->t.start());
  31.         ts.forEach(t->{
  32.             try {
  33.                 t.join();
  34.             } catch (InterruptedException e) {
  35.                 e.printStackTrace();
  36.             }
  37.         });
  38.         long end = System.nanoTime();
  39.         log.debug("adder {}, cost : {} ms",adder,(end-start)/1000_000);
  40.     }
  41. }
复制代码
  1. ##结果:
  2. 14:57:20.170 [main] DEBUG xxx - adder 2000000, cost : 49 ms
  3. 14:57:20.228 [main] DEBUG xxx - adder 2000000, cost : 43 ms
  4. 14:57:20.265 [main] DEBUG xxx - adder 2000000, cost : 36 ms
  5. 14:57:20.303 [main] DEBUG xxx - adder 2000000, cost : 37 ms
  6. 14:57:20.344 [main] DEBUG xxx - adder 2000000, cost : 41 ms
  7. 14:57:20.344 [main] DEBUG xxx - -------------
  8. 14:57:20.359 [main] DEBUG xxx - adder 2000000, cost : 13 ms
  9. 14:57:20.364 [main] DEBUG xxx - adder 2000000, cost : 5 ms
  10. 14:57:20.370 [main] DEBUG xxx - adder 2000000, cost : 5 ms
  11. 14:57:20.377 [main] DEBUG xxx - adder 2000000, cost : 6 ms
  12. 14:57:20.382 [main] DEBUG xxx - adder 2000000, cost : 4 ms
  13. ##LongAdder性能提升的原因:
  14. LongAdder性能提升的原因很简单,就是在有竞争时,设置多个累加单元,Thread-0累加Cell[0]
  15. 而Thread-1累加Cell[1]...最后将结果汇总,这样他们在累加时操作的不同的Cell变量,因此减
  16. 少了CAS重试失败,从而提高性能
复制代码
七、Unsafe

  1. ·Unsafe对象提供了非常底层的,操作内存、线程的方法
  2. ·Unsafe对象不能直接调用,只能通过反射获得
复制代码
获取Unsafe:
  1. @Slf4j
  2. public class UnsafeAccessor {
  3.     public static void main(String[] args) {
  4.         Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
  5.         theUnsafe.setAccessible(true);
  6.         Unsafe unsafe = (Unsafe) theUnsafe.get(null);
  7.         log.debug("unsafe:{}",unsafe);
  8.     }
  9. }
复制代码
Unsafe CAS操纵:
  1. /**
  2. * 使用Unsafe线程安全的操作Teacher对象的成员变量
  3. * (之前使用AtomicReferenceFieldUpdater)
  4. */
  5. @Slf4j
  6. public class UnsafeAccessor {
  7.     public static void main(String[] args) {
  8.         try {
  9.             //获取Unsafe
  10.             Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
  11.             theUnsafe.setAccessible(true);
  12.             Unsafe unsafe = (Unsafe) theUnsafe.get(null);
  13.             log.debug("unsafe:{}",unsafe);
  14.             Teacher tc = new Teacher(1,"张三");
  15.             //获取域的偏移地址
  16.             long idOffset = unsafe.objectFieldOffset(Teacher.class.getDeclaredField("id"));
  17.             long nameOffset = unsafe.objectFieldOffset(Teacher.class.getDeclaredField("name"));
  18.             //执行CAS操作
  19.             unsafe.compareAndSwapInt(tc,idOffset,1,2);
  20.             unsafe.compareAndSwapObject(tc,nameOffset,"张三","李四");
  21.             //检验
  22.             log.debug("tc : {}",tc);
  23.         } catch (NoSuchFieldException e) {
  24.             e.printStackTrace();
  25.         } catch (IllegalAccessException e) {
  26.             e.printStackTrace();
  27.         }
  28.     }
  29. }
  30. @Data
  31. @ToString
  32. @AllArgsConstructor
  33. class Teacher{
  34.     volatile int id;
  35.     volatile String name;
  36. }
复制代码
Unsafe模仿原子整数:
  1. @Slf4j
  2. public class UnsafeForAtomicInteger {
  3.     public static void main(String[] args) {
  4.         MyAtomicInteger mat = new MyAtomicInteger(10000);
  5.         List<Thread> ts = new ArrayList<>();
  6.         //1000个线程,每个线程减去10
  7.         for(int i=0;i<1000;i++){
  8.             ts.add(new Thread(()->{
  9.                 mat.decrement(10);
  10.             }));
  11.         }
  12.         ts.forEach(t->t.start());
  13.         ts.forEach(t->{
  14.             try {
  15.                 t.join();
  16.             } catch (InterruptedException e) {
  17.                 e.printStackTrace();
  18.             }
  19.         });
  20.         log.debug("mat : {}",mat.get());
  21.     }
  22. }
  23. class MyAtomicInteger{
  24.     private volatile Integer value;
  25.     private static final long valueOffset;
  26.     private static final Unsafe UNSAFE;
  27.     static{
  28.         try {
  29.             Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
  30.             theUnsafe.setAccessible(true);
  31.             UNSAFE = (Unsafe) theUnsafe.get(null);
  32.             valueOffset = UNSAFE.objectFieldOffset(MyAtomicInteger.class.getDeclaredField("value"));
  33.         } catch (NoSuchFieldException e) {
  34.             e.printStackTrace();
  35.             throw new RuntimeException();
  36.         } catch (IllegalAccessException e) {
  37.             e.printStackTrace();
  38.             throw new RuntimeException();
  39.         }
  40.     }
  41.     public MyAtomicInteger(Integer value) {
  42.         this.value = value;
  43.     }
  44.     public Integer get(){
  45.         return value;
  46.     }
  47.     public void decrement(Integer num){
  48.         while (true){
  49.             Integer prev = this.value;
  50.             Integer next = prev - num;
  51.             if(UNSAFE.compareAndSwapObject(this,valueOffset,prev,next)){
  52.                 break;
  53.             }
  54.         }
  55.     }
  56. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/) Powered by Discuz! X3.4