千家信息网

如何使用Java中无锁技术

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,本篇内容介绍了"如何使用Java中无锁技术"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、原子工具
千家信息网最后更新 2026年11月03日如何使用Java中无锁技术

本篇内容介绍了"如何使用Java中无锁技术"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

一、原子工具类

JDK 1.8 中,java.util.concurrent.atomic 包下类都是原子类,原子类都是基于 sun.misc.Unsafe 实现的。

  • CPU 为了解决并发问题,提供了 CAS 指令,全称 Compare And Swap,即比较并交互

  • CAS 指令需要 3 个参数,变量、比较值、新值。当变量的当前值与比较值相等时,才把变量更新为新值

  • CAS 是一条 CPU 指令,由 CPU 硬件级别上保证原子性

java.util.concurrent.atomic 包中的原子分为:原子性基本数据类型、原子性对象引用类型、原子性数组、原子性对象属性更新器和原子性累加器

原子性基本数据类型:AtomicBoolean、AtomicInteger、AtomicLong

原子性对象引用类型:AtomicReference、AtomicStampedReference、AtomicMarkableReference

原子性数组:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray

原子性对象属性更新:AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater

原子性累加器:DoubleAccumulator、DoubleAdder、LongAccumulator、LongAdder

修改我们之前测试原子性问题的类,使用 AtomicInteger 的简单例子

package constxiong.concurrency.a026;  import java.util.concurrent.atomic.AtomicInteger;  /**  * 测试 原子类 AtomicInteger  *   * @author ConstXiong  */ public class TestAtomicInteger {   // 计数变量  static volatile AtomicInteger count = new AtomicInteger(0);   public static void main(String[] args) throws InterruptedException {  // 线程 1 给 count 加 10000  Thread t1 = new Thread(() -> {  for (int j = 0; j <10000; j++) {  count.incrementAndGet();  }  System.out.println("thread t1 count 加 10000 结束");  });   // 线程 2 给 count 加 10000  Thread t2 = new Thread(() -> {  for (int j = 0; j <10000; j++) {  count.incrementAndGet();  }  System.out.println("thread t2 count 加 10000 结束");  });   // 启动线程 1  t1.start();  // 启动线程 2  t2.start();   // 等待线程 1 执行完成  t1.join();  // 等待线程 2 执行完成  t2.join();   // 打印 count 变量  System.out.println(count.get());  }  }

打印结果如预期

thread t2 count 加 10000 结束 thread t1 count 加 10000 结束 20000

二、线程本地存储

  • java.lang.ThreadLocal 类用于线程本地化存储。

  • 线程本地化存储,就是为每一个线程创建一个变量,只有本线程可以在该变量中查看和修改值。

  • 典型的使用例子就是,spring 在处理数据库事务问题的时候,就用了 ThreadLocal 为每个线程存储了各自的数据库连接 Connection。

  • 使用 ThreadLocal 要注意,在不使用该变量的时候,一定要调用 remove() 方法移除变量,否则可能造成内存泄漏的问题。

示例

package constxiong.concurrency.a026;  /**  * 测试 原子类 AtomicInteger  *   * @author ConstXiong  */ public class TestThreadLocal {   // 线程本地存储变量  private static final ThreadLocal THREAD_LOCAL_NUM = new ThreadLocal() {  @Override  protected Integer initialValue() {//初始值  return 0;  }  };   public static void main(String[] args) {  for (int i = 0; i <3; i++) {// 启动三个线程  Thread t = new Thread() {  @Override  public void run() {  add10ByThreadLocal();  }  };  t.start();  }  }   /**  * 线程本地存储变量加 5  */  private static void add10ByThreadLocal() {  try {  for (int i = 0; i <5; i++) {  Integer n = THREAD_LOCAL_NUM.get();  n += 1;  THREAD_LOCAL_NUM.set(n);  System.out.println(Thread.currentThread().getName() + " : ThreadLocal num=" + n);  }  } finally {  THREAD_LOCAL_NUM.remove();// 将变量移除  }  } }

每个线程最后一个值都打印到了 5

Thread-0 : ThreadLocal num=1 Thread-2 : ThreadLocal num=1 Thread-1 : ThreadLocal num=1 Thread-2 : ThreadLocal num=2 Thread-0 : ThreadLocal num=2 Thread-2 : ThreadLocal num=3 Thread-0 : ThreadLocal num=3 Thread-1 : ThreadLocal num=2 Thread-0 : ThreadLocal num=4 Thread-2 : ThreadLocal num=4 Thread-0 : ThreadLocal num=5 Thread-1 : ThreadLocal num=3 Thread-2 : ThreadLocal num=5 Thread-1 : ThreadLocal num=4 Thread-1 : ThreadLocal num=5

三、copy-on-write

根据英文名称可以看出,需要写时复制,体现的是一种延时策略。

Java 中的 copy-on-write 容器包括:CopyOnWriteArrayList、CopyOnWriteArraySet。

涉及到数组的全量复制,所以也比较耗内存,在写少的情况下使用比较适合。

简单的 CopyOnWriteArrayList 的示例,这里只是说明 CopyOnWriteArrayList 怎么用,并且是线程安全的。这个场景并不适合使用 CopyOnWriteArrayList,因为写多读少。

package constxiong.concurrency.a026;  import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.concurrent.CopyOnWriteArrayList;  /**  * 测试 copy-on-write  * @author ConstXiong  */ public class TestCopyOnWrite {   private static final Random R = new Random();    private static CopyOnWriteArrayList cowList = new CopyOnWriteArrayList(); // private static ArrayList cowList = new ArrayList();    public static void main(String[] args) throws InterruptedException {  List threadList = new ArrayList();  //启动 1000 个线程,向 cowList 添加 5 个随机整数  for (int i = 0; i <1000; i++) {  Thread t = new Thread(() -> {  for (int j = 0; j <5; j++) {  //休眠 10 毫秒,让线程同时向 cowList 添加整数,引出并发问题  try {  Thread.sleep(10);  } catch (InterruptedException e) {  e.printStackTrace();  }  cowList.add(R.nextInt(100));  }  }) ;  t.start();  threadList.add(t);  }    for (Thread t : threadList) {  t.join();  }  System.out.println(cowList.size());  } }

打印结果

5000

如果把

private static CopyOnWriteArrayList cowList = new CopyOnWriteArrayList();

改为

private static ArrayList cowList = new ArrayList();

打印结果就是小于 5000 的整数了

"如何使用Java中无锁技术"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

原子 线程 变量 存储 问题 对象 数据 类型 测试 就是 指令 数组 整数 结果 更新 技术 例子 内存 内容 属性 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技公司 有格互联网科技 广州万易互联网科技有限公司 互联网科技公司的优势 科技企业和互联网企业 上海互联网科技有限公司 狮子座互联网科技有限公司 科技创新互联网企业 广州善班互联网科技 左右互联网络科技 互联网科技生活的内容 开启互联网科技时代小说 农村开互联网科技讲堂 科技互联网的估值 剑昆互联网络科技有限公司临桂 浙江互联网科技研学营 国大互联网教育科技有限公司工作 翼展科技 首家互联网医院 互联网科技圈年度人物 南京一网一红互联网科技有限公司 亿人帮互联网科技有限公司 互联网科技工作委员会副主任毛军 互联网 的科技创新 金融科技和互联网金融 茂名市互联网科技产业园 崇明区互联网教育科技售后服务 朱啸虎曾投资哪些互联网科技企业 2021世界互联网领先科技成果发布 华人运通互联网科技公司 互联网科技创业有什么好项目
0