找网站有中文字目的,网络营销的概念和界定,做基金哪个网站好,框架做网站指的是1、线程安全和不安全定义
#xff08;1#xff09;、线程安全
线程安全是指一个类或方法在被多个线程访问的情况下可以正确得到结果#xff0c;不会出现数据不一致或其他错误行为。
线程安全的条件
1、原子性#xff08;Atomicity#xff09;
多个操作要么全部完成1、线程安全
线程安全是指一个类或方法在被多个线程访问的情况下可以正确得到结果不会出现数据不一致或其他错误行为。
线程安全的条件
1、原子性Atomicity
多个操作要么全部完成要么一个也不完成中间状态对外部不可见。
2、可见性Visibility
一个线程对共享变量的修改对其他线程是立即可见的。
3、有序性Ordering
操作的顺序应该按照预期的顺序执行不会由于编译器优化或处理器乱序执行而改变。
4、互斥性Mutual Exclusion
在任何时刻只有一个线程可以访问共享资源避免多个线程同时修改同一数据。
2、线程不安全
线程不安全是指一个类或方法在多线程环境下不能被多个线程安全地访问可能会导致数据不一致或其他错误行为。
线程不安全可能会出现的问题
1、数据竞争Race Conditions
多个线程同时访问和修改同一个共享变量导致结果不可预测。 即多个线程同时修改一个共享变量可能导致结果达不到预期。
代码示例 public class Counter {private int counter 0;public void incrementCounter() {counter; // 不是原子操作可能会导致数据竞争}}2、内存可见性问题Visibility Problems
一个线程对共享变量的修改对其他线程不可见导致数据不一致。
即每个线程运行时都会先从主内存中读取变量到工作内存中保存副本。执行修改操作都是在自己的工作内存中进行的修改结果会先保存到工作副本中只有遇到合适的机制或处理完成后才会将修改的变量副本数据写回到主内存中。所以在此期间即使修改了数据可能结果也不会被其他线程知道导致获取的还是之前的数据。
3、死锁Deadlocks
多个线程互相等待对方释放锁导致程序挂起。
代码示例
public class DeadlockExample {private final Object lock1 new Object();private final Object lock2 new Object();public void method1() {synchronized (lock1) {synchronized (lock2) {// 业务逻辑}}}public void method2() {synchronized (lock2) {synchronized (lock1) {// 业务逻辑}}}}2、常用解决不安全方式
1、java.util.concurrent的工具类
java.util.concurrent中提供了很多保障线程安全的工具类如BlockingQueueCountdownLatch等可以参考之前的博客了解下。
2、synchronized
使用 synchronized关键字实现同步确保同一时间只有一个线程可以访问共享资源。
代码示例 public synchronized void incrementCounter() {counter;}3、Lock
使用Lock或和Condition结合的方式可以实现更加灵活的锁机制保证线程同步执行
4、Lock和synchronized区别
1、synchronized是一个关键字可以直接应用于方法或代码块。Lock 是一个接口提供了比synchronized 更丰富的锁操作。 2、synchronized当同步代码块或方法执行完毕或抛出异常时锁会自动释放。Lock需要手动获取和释放锁通常在 try-finally 块中使用确保锁在任何情况下都能被释放。 3、synchronized锁是非公平的即等待时间最长的线程不一定最先获得锁。ReentrantLock可以选择是否使用公平锁。公平锁确保等待时间最长的线程最先获得锁。
Lock lock new ReentrantLock(true); // 公平锁4、synchronized锁的粒度是对象级别的即一个对象的多个同步方法之间会相互阻塞。Lock可以更细粒度地控制锁允许多个锁实例从而减少不必要的阻塞。 5、条件变量不一样synchronized内使用Object类的wait和notify方法Lock提供了Condition接口通过await和signal方法实现线程等待唤醒机制。 代码示例
Lock lock new ReentrantLock();Condition condition lock.newCondition();try {lock.lock();// 等待条件condition.await();// 通知条件condition.signal();} catch (InterruptedException e) {// 处理中断异常} finally {lock.unlock();}6、synchronized而言获取锁的线程和等待获取锁的线程都是不可中断的Lock可以通过灵活的机制控制是否可被中断。 Lock可中断获取锁代码示例 如下的代码中通过lock.lockInterruptibly()可中断的获取锁那么被中断时会直接中断抛出异常如果是lock.lock()获取锁那么就和synchronized一样任然会继续执行。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockExample {private final Lock lock new ReentrantLock();public void method() throws InterruptedException {try {System.out.println(Thread Thread.currentThread().getName() is trying to acquire the lock...);lock.lockInterruptibly(); // 可中断地获取锁被中断时直接抛出中断异常System.out.println(Thread Thread.currentThread().getName() got the lock.);Thread.sleep(10000); // 模拟长时间操作} catch (InterruptedException e) {System.out.println(Thread Thread.currentThread().getName() was interrupted.);throw e;} finally {lock.unlock();}}public static void main(String[] args) {LockExample example new LockExample();Thread t1 new Thread(() - {try {example.method();} catch (InterruptedException e) {System.out.println(Thread Thread.currentThread().getName() was interrupted.);}});Thread t2 new Thread(() - {try {example.method();} catch (InterruptedException e) {System.out.println(Thread Thread.currentThread().getName() was interrupted.);}});t1.start();t2.start();// 让主线程等待一段时间确保t1已经进入同步代码块try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}// 中断t2线程t2.interrupt();}
}5、ThreadLocal
使用 ThreadLocal变量确保每个线程都有自己的独立副本避免线程间的竞争。 线程安全问题的核心在于多个线程会对同一个临界区共享资源进行操作如果每个线程都使用自己的“共享资源”各自使用各自的又互相不影响到彼此即让多个线程间达到隔离的状态这样就不会出现线程安全的问题。ThreadLocal是一种“空间换时间”的方案每个线程都会都拥有自己的“共享资源”无疑内存会大很多但是由于不需要同步也就减少了线程可能存在的阻塞等待的情况从而提高的时间效率。
代码示例
public class ThreadSafeCounter {private ThreadLocalInteger counter ThreadLocal.withInitial(() - 0);public void incrementCounter() {counter.set(counter.get() 1);}public int getCounter() {return counter.get();}
}6、Redis分布式锁
以上都是基于单节点下的如果是多节点集群模式仍然不能保证整个系统的线程安全问题。 可以将服务的多个节点都配置到同一个redis连接利用redis的setNx原子操作来实现锁的功能如果set Key成功认为获取了锁使用删除key实现解锁的功能这个是实际应用中常用的。
redis分布式锁和synchronized的区别 1、分布式锁是指在分布式环境下的多个节点之间控制并发访问的一种机制而synchronized是在单个服务的线程之间进行同步控制 2、分布式锁一般通过Redis等分布式数据库实现可以在多个应用服务器之间共享而synchronized则只能在单个应用进程内起作用。 3、分布式锁需要考虑分布式环境下的数据一致性问题保证多个节点之间的数据同步而synchronized只需要考虑单个进程内的数据同步问题。 4、Redis等分布式数据库提供的分布式锁机制可以实现比较灵活的锁定方式如设置超时时间、可重入等功能而synchronized没有这些灵活的操作。
7、使用安全容器
Java的集合容器主要有四大类别List、Set、Queue、Map常见的集合类ArrayList、LinkedList、HashMap这些容器都是非线程安全的容器。 如果有多个线程并发地访问这些容器时就可能会出现问题。因此在编写程序时在多线程环境下必须要求程序员手动地在任何访问到这些容器的地方进行同步处理这样导致在使用这些容器的时候非常地不方便。 所以java提供了线程安全的容器其中按照底层实现原理可以分为同步容器和并发容器。这个在后面会介绍。
8、使用Atomic原子类
使用 java.util.concurrent.atomic 包中的原子类如 AtomicInteger、AtomicLong 等这些类提供了原子操作。
代码示例
import java.util.concurrent.atomic.AtomicInteger;
public class Counter {private AtomicInteger counter new AtomicInteger(0);public void incrementCounter() {counter.incrementAndGet();}
}3、安全容器
1、同步容器
1、概述
同步容器Synchronized Containers是 Java 提供的一种线程安全的集合类它们通过在方法内部添加同步机制来确保线程安全。Java 标准库中的 Collections 类提供了一些静态方法可以将普通的集合类转换为同步集合类。 同步容器可以简单地理解为使用synchronized实现同步后的容器。
2、常见的同步容器
1、Vector
Vector 是一个线程安全的动态数组类似于 ArrayList但它的方法都是同步的。
代码示例 VectorString vector new Vector();vector.add(Hello);vector.add(World);2、Hashtable
Hashtable 是一个线程安全的哈希表类似于 HashMap但它的方法都是同步的。
代码示例 HashtableString, String hashtable new Hashtable();hashtable.put(key1, value1);hashtable.put(key2, value2);3、Collections.synchronizedList
将一个 List 转换为同步的 List。
代码示例 ListString list Collections.synchronizedList(new ArrayList());list.add(Hello);list.add(World);4、Collections.synchronizedMap
将一个 Map 转换为同步的 Map。
代码示例 MapString, String map Collections.synchronizedMap(new HashMap());map.put(key1, value1);map.put(key2, value2);5、Collections.synchronizedSet
将一个 Set 转换为同步的 Set。
代码示例 SetString set Collections.synchronizedSet(new HashSet());set.add(Hello);set.add(World);3、同步容器的工作原理
同步容器通过在每个方法内部添加synchronized 关键字来实现线程安全。例如Collections.synchronizedList 返回的列表对象的方法内部都会加上synchronized 关键字确保同一时间只有一个线程可以访问该方法。
4、使用同步容器的注意事项
1、性能影响
同步容器在高并发环境下可能会成为性能瓶颈因为每次方法调用都会阻塞其他线程。对于高性能要求的场景可以考虑使用 ConcurrentHashMap 或 CopyOnWriteArrayList 等并发集合类。
2、外部同步
尽管同步容器的方法是线程安全的但在进行复合操作如迭代即遍历时仍然需要外部同步。
代码示例 ListString list Collections.synchronizedList(new ArrayList());synchronized (list) {IteratorString iterator list.iterator();while (iterator.hasNext()) {System.out.println(iterator.next());}}2、并发容器
1、概述
并发容器Concurrent Containers是专门为多线程环境设计的集合类它们提供了比同步容器更高的并发性能和更好的扩展性。Java 提供了多种并发容器这些容器在设计上考虑了多线程并发访问的场景能够在高并发环境下保持良好的性能和安全性。
2、常见的并发容器
1、ConcurrentHashMap
ConcurrentHashMap是一个线程安全的哈希表它允许多个线程同时读取和写入而不会造成死锁。 内部使用分段锁Segment机制允许多个线程同时访问不同的段从而提高并发性能。
代码示例 import java.util.concurrent.ConcurrentHashMap;public class ConcurrentHashMapExample {public static void main(String[] args) {ConcurrentHashMapString, String map new ConcurrentHashMap(); // 正常当map用即可map.put(key1, value1);map.put(key2, value2);String value map.get(key1);System.out.println(value); // 输出: value1}}2、CopyOnWriteArrayList
CopyOnWriteArrayList是一个线程安全的列表它在写操作时会复制整个数组因此读操作不需要加锁写操作也相对安全。 适用于读多写少的场景。
代码示例 import java.util.concurrent.CopyOnWriteArrayList;public class CopyOnWriteArrayListExample {public static void main(String[] args) {CopyOnWriteArrayListString list new CopyOnWriteArrayList(); // 正常当List用即可list.add(Hello);list.add(World);for (String item : list) {System.out.println(item); // 输出: Hello, World}}}3、ConcurrentLinkedQueue
ConcurrentLinkedQueue 是一个线程安全的无界非阻塞队列适用于高并发环境。 内部使用链表结构允许多个线程同时进行插入和删除操作。
代码示例 import java.util.concurrent.ConcurrentLinkedQueue;public class ConcurrentLinkedQueueExample {public static void main(String[] args) {ConcurrentLinkedQueueString queue new ConcurrentLinkedQueue();queue.offer(Hello);queue.offer(World);String item queue.poll();System.out.println(item); // 输出: Hello}}4、ConcurrentSkipListMap
ConcurrentSkipListMap 是一个线程安全的有序映射类似于TreeMap但它使用跳表Skip List实现允许多个线程并发访问。 适用于需要有序存储且支持并发访问的场景。
代码示例 import java.util.concurrent.ConcurrentSkipListMap;public class ConcurrentSkipListMapExample {public static void main(String[] args) {ConcurrentSkipListMapString, String map new ConcurrentSkipListMap();map.put(key1, value1);map.put(key2, value2);String value map.get(key1);System.out.println(value); // 输出: value1}}5、ConcurrentLinkedDeque
ConcurrentLinkedDeque 是一个线程安全的双端队列适用于高并发环境。 内部使用链表结构允许多个线程同时进行插入和删除操作。
代码示例 import java.util.concurrent.ConcurrentLinkedDeque;public class ConcurrentLinkedDequeExample {public static void main(String[] args) {ConcurrentLinkedDequeString deque new ConcurrentLinkedDeque();deque.offerFirst(Hello);deque.offerLast(World);String item deque.pollFirst();System.out.println(item); // 输出: Hello}}6、CopyOnWriteArraySet
CopyOnWriteArraySet 是 Java 提供的一个线程安全的集合类它是基于 CopyOnWriteArrayList 实现的。 CopyOnWriteArraySet 适用于读多写少的场景因为它在的修改操作如添加、删除都会创建一个新的底层数组并且在写操作期间锁定整个集合确保操作的原子性和一致性。
代码示例
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArraySet;public class CopyOnWriteArraySetExample {public static void main(String[] args) {// 创建一个 CopyOnWriteArraySetCopyOnWriteArraySetString set new CopyOnWriteArraySet();// 添加元素set.add(Apple);set.add(Banana);set.add(Cherry);// 检查元素是否存在System.out.println(Contains Banana: set.contains(Banana)); // 输出: Contains Banana: true// 删除元素set.remove(Banana);// 检查元素是否存在System.out.println(Contains Banana: set.contains(Banana)); // 输出: Contains Banana: false// 获取集合大小System.out.println(Size of set: set.size()); // 输出: Size of set: 2// 遍历集合System.out.println(Elements in set:);IteratorString iterator set.iterator();while (iterator.hasNext()) {System.out.println(iterator.next());}// 输出: Apple, Cherry}
}3、并发容器的特点
1、高并发性能 并发容器设计时考虑了多线程并发访问的场景通常使用细粒度的锁或无锁算法允许多个线程同时访问不同的部分从而提高并发性能。
2、线程安全 并发容器在多线程环境下是安全的不会导致数据不一致或其他错误行为。
3、扩展性 并发容器通常具有更好的扩展性能够在高并发环境下保持良好的性能。
4、适用场景
ConcurrentHashMap适用于需要线程安全的哈希表读多写少的场景。CopyOnWriteArrayList适用于读多写少的场景读操作不需要加锁。ConcurrentLinkedQueue适用于高并发环境下的队列操作。ConcurrentSkipListMap适用于需要有序存储且支持并发访问的场景。ConcurrentLinkedDeque适用于高并发环境下的双端队列操作。
4、同步容器和并发容器对比
同步容器 同步容器通过在方法内部添加 synchronized 关键字来实现线程安全使用起来非常简单。 例如Vector 和 Hashtable 是直接提供的线程安全版本无需额外的操作。
但同步容器在高并发环境下可能会成为性能瓶颈因为每次方法调用都会阻塞其他线程。如Vector 的 add 方法在每次调用时都会加锁导致其他线程无法同时进行操作。 尽管同步容器的方法是线程安全的但在进行复合操作如迭代时仍然需要外部同步。 同步容器的同步机制较为单一无法灵活调整锁的粒度和类型。
并发容器 并发容器设计时考虑了多线程并发访问的场景通常使用细粒度的锁或无锁算法允许多个线程同时访问不同的部分从而提高并发性能。 如ConcurrentHashMap 使用分段锁机制允许多个线程同时访问不同的段。 并发容器在多线程环境下是安全的不会导致数据不一致或其他错误行为。 并发容器提供了更多的灵活性允许开发者根据具体的并发需求选择合适的锁机制和数据结构。如CopyOnWriteArrayList 适用于读多写少的场景ConcurrentLinkedQueue 适用于高并发环境下的队列操作。 并发容器通常提供了更多的高级功能如 ConcurrentHashMap 的 computeIfAbsent 方法可以在并发环境下安全地进行计算。
但并发容器的使用和理解相对复杂需要开发者对并发编程有较深入的理解。如ConcurrentHashMap 的分段锁机制需要理解其内部实现才能有效使用。 并发容器在初始化时可能会有一定的开销但这种开销通常在后续的高并发操作中会被抵消。
对比
5、总结
对于简单的同步需求和低并发场景同步容器是一个不错的选择而对于复杂的同步需求和高并发场景建议使用并发容器。
4、Fork/Join框架
1、概述
Fork/Join 框架是 Java 中用于实现并行任务处理的一种高级并发框架。它特别适用于可以分解成多个子任务并最终合并结果的场景。 Fork/Join 框架的核心思想是“分而治之”通过递归地将大任务分解成小任务然后将这些小任务并行处理最后合并各个子任务的结果。
2、主要组件
1、ForkJoinPool
ForkJoinPool 是 Fork/Join 框架的执行器负责管理和调度任务。它使用工作窃取Work Stealing算法来提高任务的并行处理效率。工作窃取算法允许空闲的工作线程从其他忙碌的工作线程的任务队列中“窃取”任务来执行从而最大化 CPU 的利用率。
2、RecursiveTask
RecursiveTask 是一个抽象类用于表示可以返回结果的任务。继承 RecursiveTask 类并实现 compute 方法该方法定义了任务的执行逻辑包括任务的分解和结果的合并。
3、RecursiveAction
RecursiveAction 是一个抽象类用于表示不返回结果的任务。继承 RecursiveAction 类并实现 compute 方法该方法定义了任务的执行逻辑包括任务的分解和执行。
3、工作流程
1、任务提交
将任务提交给 ForkJoinPool通常通过调用 invoke 方法来启动任务会调用任务的compute方法。
2、任务分解
在任务的 compute 方法中将大任务分解成多个子任务使用 fork 方法将子任务提交给 ForkJoinPool。
3、任务执行
ForkJoinPool 负责调度和执行这些子任务使用工作窃取算法来优化任务的并行处理。即要包含最终子任务的处理逻辑。
4、结果合并
子任务完成后使用 join 方法获取子任务的结果并在 compute 方法中合并这些结果。
4、示例代码
假设我们需要计算一个大数组的总和可以使用 Fork/Join 框架来实现并行计算。
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;public class ForkJoinSumCalculator extends RecursiveTaskLong {private final long[] array;private final int start;private final int end;private static final int THRESHOLD 1000; // 阈值用于决定是否分解任务public ForkJoinSumCalculator(long[] array, int start, int end) {this.array array;this.start start;this.end end;}Overrideprotected Long compute() {if (end - start THRESHOLD) { // 当任务足够小时直接计算结果long sum 0;for (int i start; i end; i) {sum array[i];}return sum;} else { // 当任务比较大时做任务拆分int middle (start end) / 2;ForkJoinSumCalculator leftTask new ForkJoinSumCalculator(array, start, middle); // 构建的子任务对主任务分解ForkJoinSumCalculator rightTask new ForkJoinSumCalculator(array, middle, end);// 提交子任务leftTask.fork(); // 提交子任务如果子任务任然超出阈值还会走else部分进行分解任务相当于递归直到任务小于阈值会走上面的if部分处理得到结果。rightTask.fork();// 合并子任务的结果return leftTask.join() rightTask.join(); // 结果直接通过join返回}}public static void main(String[] args) {long[] array new long[1000000];for (int i 0; i array.length; i) {array[i] i;}ForkJoinPool forkJoinPool new ForkJoinPool(); // 创建调度器ForkJoinSumCalculator task new ForkJoinSumCalculator(array, 0, array.length); // 创建任务继承RecursiveTask需要返回或RecursiveAction不需要返回long result forkJoinPool.invoke(task); // 调度执行任务invoke实际只是调用compute方法获取任务最终结果System.out.println(Sum: result);}
}5、总结
使用 Fork/Join 框架可以显著提高多核处理器的利用率从而提升程序的性能。适用于可以分解成多个子任务并最终合并结果的场景。开发者只需关注任务的分解和合并逻辑。
但是任务分解和合并需要一定的开销特别是对于小任务可能会导致性能下降。需要合理设置阈值平衡任务分解的开销和并行处理的收益。大量的任务分解会导致内存开销增加特别是在任务数量较多时。
5、原子操作类
Atomic类是JUC提供的一组原子操作的封装类它们位于java.util.concurrent.atomic中。Atomic包一共提供了13个类。 Atomic类是通过无锁lock-free的方式实现的线程安全thread-safe访问。它的主要原理是利用了CASCompare and Set。
Atomic包中的类基本的特性就是在多线程环境下当有多个线程同时对单个包括基本类型及引用类型变量进行操作时具有排他性即当多个线程同时对该变量的值进行更新时仅有一个线程能成功而未成功的线程可以向自旋锁一样继续尝试一直等到执行成功。
1、原子基本数据类型
如AtomicInteger是一个线程安全的整数类提供了原子性的增减操作和其他常用的原子操作。
1、主要方法
int get()获取当前值。void set(int newValue)设置新值。int getAndSet(int newValue)获取当前值并设置新值。 // 都是先用后增思路即aint getAndIncrement()获取当前值并自增1。int getAndDecrement()获取当前值并自减1。int getAndAdd(int delta)获取当前值并增加指定值。boolean compareAndSet(int expect, int update)如果当前值等于预期值则设置新值并返回 true否则返回 false。
示例代码
import java.util.concurrent.atomic.AtomicInteger;public class AtomicIntegerExample {public static void main(String[] args) {AtomicInteger atomicInt new AtomicInteger(0);// 自增1int value atomicInt.getAndIncrement();System.out.println(Value after increment: value); // 输出: Value after increment: 0// 设置新值atomicInt.set(10);System.out.println(New value: atomicInt.get()); // 输出: New value: 10// 比较并设置boolean result atomicInt.compareAndSet(10, 20);System.out.println(Compare and set result: result); // 输出: Compare and set result: trueSystem.out.println(Current value: atomicInt.get()); // 输出: Current value: 20}
}2、原子数组
如AtomicIntegerArray 是一个线程安全的整数数组类提供了对数组元素的原子操作。
1、主要方法
int get(int index)获取指定索引处的值。void set(int index, int value)设置指定索引处的值。int getAndSet(int index, int value)获取指定索引处的值并设置新值。int getAndIncrement(int index)获取指定索引处的值并自增1。int getAndDecrement(int index)获取指定索引处的值并自减1。int getAndAdd(int index, int delta)获取指定索引处的值并增加指定值。boolean compareAndSet(int index, int expect, int update)如果指定索引处的值等于预期值则设置新值并返回 true否则返回 false。
示例代码
import java.util.concurrent.atomic.AtomicIntegerArray;public class AtomicIntegerArrayExample {public static void main(String[] args) {int[] values {1, 2, 3};AtomicIntegerArray atomicIntArray new AtomicIntegerArray(values);// 获取指定索引处的值int value atomicIntArray.get(0);System.out.println(Value at index 0: value); // 输出: 1// 返回索引处的值并自增1返回结果为自增前的结果即先用后加类似avalue atomicIntArray.getAndIncrement(0);System.out.println(Value after increment at index 0: value); // 输出: 1// 比较并设置值上面自增过了所以0处索引的值为2和预期值相等返回true同时在设置为10boolean result atomicIntArray.compareAndSet(0, 2, 10);System.out.println(Compare and set result: result); // 输出: trueresult atomicIntArray.compareAndSet(0, 1, 20); System.out.println(Compare and set result: result); // 输出: falseSystem.out.println(Current value at index 0: atomicIntArray.get(0)); // 输出: 10}
}3、原子更新引用类
如AtomicReference是一个线程安全的引用类提供了对对象引用的原子操作。
1、主要方法
T get()获取当前值。void set(T value)设置新值。T getAndSet(T value)获取当前值并设置新值。boolean compareAndSet(T expect, T update)如果当前值等于预期值则设置新值并返回 true否则返回 false。
示例代码
import java.util.concurrent.atomic.AtomicReference;public class AtomicReferenceExample {public static void main(String[] args) {AtomicReferenceString atomicRef new AtomicReference(Hello);// 获取当前值String value atomicRef.get();System.out.println(Initial value: value); // 输出: Initial value: Hello// 设置新值atomicRef.set(World);System.out.println(New value: atomicRef.get()); // 输出: New value: World// 比较并设置boolean result atomicRef.compareAndSet(World, Java);System.out.println(Compare and set result: result); // 输出: Compare and set result: trueSystem.out.println(Current value: atomicRef.get()); // 输出: Current value: Java}
}4、原子更新字段类
如AtomicIntegerFieldUpdater是一个用于更新对象字段的原子类适用于需要对对象的某个字段进行原子操作的场景。它通过反射机制来实现对字段的原子操作。
1、主要方法
static AtomicIntegerFieldUpdaterT newUpdater(ClassT tclass, String fieldName)创建一个新的 AtomicIntegerFieldUpdater 实例。int get(T obj)获取指定对象的字段值。void set(T obj, int newValue)设置指定对象的字段值。int getAndSet(T obj, int newValue)获取指定对象的字段值并设置新值。int getAndIncrement(T obj)获取指定对象的字段值并自增1。int getAndDecrement(T obj)获取指定对象的字段值并自减1。int getAndAdd(T obj, int delta)获取指定对象的字段值并增加指定值。boolean compareAndSet(T obj, int expect, int update)如果指定对象的字段值等于预期值则设置新值并返回 true否则返回 false。
示例代码
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;class MyObject {volatile int value;
}public class AtomicIntegerFieldUpdaterExample {
public static void main(String[] args) {// 定义MyObject类的更新对象指定value属性AtomicIntegerFieldUpdaterMyObject updater AtomicIntegerFieldUpdater.newUpdater(MyObject.class, value);// MyObject 实例对象ojMyObject obj new MyObject();// 通过更新类赋值obj的value属性为0updater.set(obj, 0);System.out.println(Initial value: updater.get(obj)); // 输出: Initial value: 0// 通过更新类将obj的value属性自增1int value updater.getAndIncrement(obj);System.out.println(Value after increment: value); // 输出: Value after increment: 0// 通过更新类将obj的value属性对比和重新赋值boolean result updater.compareAndSet(obj, 1, 10);System.out.println(Compare and set result: result); // 输出: Compare and set result: true// 通过更新类获取obj的value属性值System.out.println(Current value: updater.get(obj)); // 输出: Current value: 10}
}学海无涯苦作舟