线程安全和不可变性(Thread Safety and Immutability)

2023-12-03 04:08

本文主要是介绍线程安全和不可变性(Thread Safety and Immutability),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文链接:http://tutorials.jenkov.com/java-concurrency/thread-safety-and-immutability.html

竞争条件只会在多个线程访问相同的资源并且一个或多个线程改写这个资源的情况下发生。如果多个线程只是同时读取相同的资源不会导致竞争条件的发生。

我们可以通过某种手段让共享的对象不可改变,从而可以确保这些不可改变的共享对象不会被任何一个线程改变,因此这些不可改变的对象是线程安全的。下面是一个例子:

    public class ImmutableValue {private int value = 0;public Immutablevalue(int value) {this.value = value;}public int getValue() {return this.value;}}

注意,ImmutableValue 类的实例的值是通过构造方法传递的、 ImmutableValue 类是没有 set 方法的,一旦 ImmutableValue 类的实例被创建以后就不能改变它的值。 ImmutableValue 类的实例是不可改变的,可以通过 getValue() 方法来读取它的值。

如果需要在这个 ImmutableValue 类的实例上执行操作,可以把不可变对象原有的值结合需要的操作产生一个新的值,然后用这个新的值新建一个实例,最后把这个新建的实例返回。下面是一个 add 操作的例子:

    public class ImmutableValue {private int value = 0;public ImmutableValue(int value) {this.value = value; }public int getValue() {return this.value;}public ImmutableValue add(int valueToAdd) {return new ImmutableValue(this.value + valueToAdd);}}

注意, add() 方法用 add 操作的结果重新构造了一个 ImmutableValue 类的实例并返回,而不是直接对原来的不可变对象的值 value 做 add 操作。

引用不是线程安全的!

记住,即使一个对象是不可变的因此这个对象是线程安全的,但这个对象的引用未必是线程安全的。看下面的例子:

    public class Calculator {private ImmutableValue currentValue = null;public ImmutableValue getValue() {return currentValue;}public void setValue(ImmutableValue newValue) {this.currentValue = newValue;}public void add(int newValue) {this.currentValue = this.currentValue.add(newValue);}}

Calculator 类持有 ImmutableValue 类的实例的一个引用。注意,可以通过 setValue() 和 add() 方法来改变这个引用指向的对象。因此,即使 Calculator 类在内部使用了一个不可变的对象,但并不是说这个 Calculator 类就不可改变,它还是线程不安全的。换句话说, ImmutableValue 类是线程安全的,但使用了这个类的类未必也是线程安全的。这是通过不可变性来达到线程安全时需要注意的问题。

为了使 Calculator 类达到线程安全,可以在 getValue()、 setValue() 和 add() 方法前声明为 synchronized 方法。声明为 synchronized 方法消除了这个问题。

Next: Java 内存模型

这篇关于线程安全和不可变性(Thread Safety and Immutability)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/448010

相关文章

在Java中实现线程之间的数据共享的几种方式总结

《在Java中实现线程之间的数据共享的几种方式总结》在Java中实现线程间数据共享是并发编程的核心需求,但需要谨慎处理同步问题以避免竞态条件,本文通过代码示例给大家介绍了几种主要实现方式及其最佳实践,... 目录1. 共享变量与同步机制2. 轻量级通信机制3. 线程安全容器4. 线程局部变量(ThreadL

Linux线程同步/互斥过程详解

《Linux线程同步/互斥过程详解》文章讲解多线程并发访问导致竞态条件,需通过互斥锁、原子操作和条件变量实现线程安全与同步,分析死锁条件及避免方法,并介绍RAII封装技术提升资源管理效率... 目录01. 资源共享问题1.1 多线程并发访问1.2 临界区与临界资源1.3 锁的引入02. 多线程案例2.1 为

Java Thread中join方法使用举例详解

《JavaThread中join方法使用举例详解》JavaThread中join()方法主要是让调用改方法的thread完成run方法里面的东西后,在执行join()方法后面的代码,这篇文章主要介绍... 目录前言1.join()方法的定义和作用2.join()方法的三个重载版本3.join()方法的工作原

Java中的xxl-job调度器线程池工作机制

《Java中的xxl-job调度器线程池工作机制》xxl-job通过快慢线程池分离短时与长时任务,动态降级超时任务至慢池,结合异步触发和资源隔离机制,提升高频调度的性能与稳定性,支撑高并发场景下的可靠... 目录⚙️ 一、调度器线程池的核心设计 二、线程池的工作流程 三、线程池配置参数与优化 四、总结:线程

WinForm跨线程访问UI及UI卡死的解决方案

《WinForm跨线程访问UI及UI卡死的解决方案》在WinForm开发过程中,跨线程访问UI控件和界面卡死是常见的技术难题,由于Windows窗体应用程序的UI控件默认只能在主线程(UI线程)上操作... 目录前言正文案例1:直接线程操作(无UI访问)案例2:BeginInvoke访问UI(错误用法)案例

Nginx安全防护的多种方法

《Nginx安全防护的多种方法》在生产环境中,需要隐藏Nginx的版本号,以避免泄漏Nginx的版本,使攻击者不能针对特定版本进行攻击,下面就来介绍一下Nginx安全防护的方法,感兴趣的可以了解一下... 目录核心安全配置1.编译安装 Nginx2.隐藏版本号3.限制危险请求方法4.请求限制(CC攻击防御)

Linux线程之线程的创建、属性、回收、退出、取消方式

《Linux线程之线程的创建、属性、回收、退出、取消方式》文章总结了线程管理核心知识:线程号唯一、创建方式、属性设置(如分离状态与栈大小)、回收机制(join/detach)、退出方法(返回/pthr... 目录1. 线程号2. 线程的创建3. 线程属性4. 线程的回收5. 线程的退出6. 线程的取消7.

Linux下进程的CPU配置与线程绑定过程

《Linux下进程的CPU配置与线程绑定过程》本文介绍Linux系统中基于进程和线程的CPU配置方法,通过taskset命令和pthread库调整亲和力,将进程/线程绑定到特定CPU核心以优化资源分配... 目录1 基于进程的CPU配置1.1 对CPU亲和力的配置1.2 绑定进程到指定CPU核上运行2 基于

Javaee多线程之进程和线程之间的区别和联系(最新整理)

《Javaee多线程之进程和线程之间的区别和联系(最新整理)》进程是资源分配单位,线程是调度执行单位,共享资源更高效,创建线程五种方式:继承Thread、Runnable接口、匿名类、lambda,r... 目录进程和线程进程线程进程和线程的区别创建线程的五种写法继承Thread,重写run实现Runnab

SpringBoot线程池配置使用示例详解

《SpringBoot线程池配置使用示例详解》SpringBoot集成@Async注解,支持线程池参数配置(核心数、队列容量、拒绝策略等)及生命周期管理,结合监控与任务装饰器,提升异步处理效率与系统... 目录一、核心特性二、添加依赖三、参数详解四、配置线程池五、应用实践代码说明拒绝策略(Rejected