JUC-变量的线程安全

news2024/9/23 3:26:57

成员变量和静态变量是否线程安全?

  • 如果它们没有共享,则线程安全,即没有被外部访问

  • 如果它们被共享了,根据它们的状态是否能够改变,又分两种情况

    • 如果只有读操作,则线程安全

    • 如果有读写操作,则这段代码是临界区,需要考虑线程安全

局部变量是否线程安全?

  • 局部变量是线程安全的

  • 但局部变量引用的对象则未必

    • 如果该对象没有逃离方法的作用访问,它是线程安全的

    • 如果该对象逃离方法的作用范围,需要考虑线程安全

局部变量线程安全分析

 public static void test1() {
    int i = 10;
    i++;
}

每个线程调用 test1() 方法时局部变量 i,会在每个线程的栈帧内存中被创建多份,因此不存在共享,局部变量随着线程的创建而创建,每个线程都有独立的局部变量,不共享,这就避免了线程安全问题,如图

 局部变量的引用

成员变量

class ThreadUnsafe {
    ArrayList<String> list = new ArrayList<>();
    public void method1(int loopNumber) {
        for (int i = 0; i < loopNumber; i++) {
            // { 临界区, 会产生竞态条件
            method2();
            method3();
            // } 临界区
        }
    }
    private void method2() {
        list.add("1");
    }
    private void method3() {
        list.remove(0);
    }
}

  开启两个线程任务执行method1

static final int THREAD_NUMBER = 2;
static final int LOOP_NUMBER = 200;
public static void main(String[] args) {
    ThreadUnsafe test = new ThreadUnsafe();
    for (int i = 0; i < THREAD_NUMBER; i++) {
        new Thread(() -> {
            test.method1(LOOP_NUMBER);
        }, "Thread" + i).start();
    }
}

其中一种情况就是,如果线程2 还未 add,线程1 remove 就会报错

Exception in thread "Thread1" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0 
 at java.util.ArrayList.rangeCheck(ArrayList.java:657) 
 at java.util.ArrayList.remove(ArrayList.java:496) 
 at cn.itcast.n6.ThreadUnsafe.method3(TestThreadSafe.java:35) 
 at cn.itcast.n6.ThreadUnsafe.method1(TestThreadSafe.java:26) 
 at cn.itcast.n6.TestThreadSafe.lambda$main$0(TestThreadSafe.java:14) 
 at java.lang.Thread.run(Thread.java:748) 

无论哪个线程中的 method2 引用的都是同一个对象中的 list 成员变量,method3 与 method2 分析相同,由于多线程执行顺序不可控,线程一尚未add,发生了线程的上下文切换,线程二就进行remove就会报错

 

局部变量 

如果将list修改为局部变量,那么就不会有上述问题了

分析:

  • list 是局部变量,每个线程调用时会创建其不同实例,没有共享

  • 而 method2 的参数是从 method1 中传递过来的,与 method1 中引用同一个对象

  • method3 的参数分析与 method2 相同

 

方法访问修饰符带来的思考,如果把 method2 和 method3 的方法修改为 public 会不会代理线程安全问题?

  • 情况1:有其它线程调用 method2 和 method3

  • 情况2:在 情况1 的基础上,为 ThreadSafe 类添加子类,子类覆盖 method2 或 method3 方法,此时会调用子类重写的方法,则会造成新的线程安全问题,所以要合理使用private 或 final 来保证方法不被子类重写而造成线程安全问题

class ThreadSafe {
    public final void method1(int loopNumber) {
        ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < loopNumber; i++) {
            method2(list);
            method3(list);
        }
    }
    private void method2(ArrayList<String> list) {
        list.add("1");
    }
    private void method3(ArrayList<String> list) {
        list.remove(0);
    }
}
class ThreadSafeSubClass extends ThreadSafe{
    @Override
    public void method3(ArrayList<String> list) {
        new Thread(() -> {
            list.remove(0);
        }).start();
    }
}

常见线程安全类

  • String

  • Integer

  • StringBuffer

  • Random

  • Vector

  • Hashtable

  • java.util.concurrent 包下的类

这里说它们是线程安全的是指,多个线程调用它们同一个实例的某个方法时,是线程安全的。也可以理解为

  • 它们的每个方法单独使用是原子的,因为方法内部都有上锁

  • 但注意它们多个方法的组合不是原子的,只在方法内部上锁,方法之间的调用可能会出现线程的上下文切换,还是线程不安全

线程安全类方法的组合

Hashtable table = new Hashtable();
// 线程1,线程2
if( table.get("key") == null) {
    table.put("key", value);
}

 线程1发现key为null,执行put操作,此时进行了线程的上下文切换,线程2也发现此时为null,也进行put操作,就出现了线程不安全的情况

不可变类线程安全性

String、Integer 等都是不可变类,因为其内部的状态不可以改变,因此它们的方法都是线程安全的 有同学或许有疑问,String 有 replace,substring 等方法【可以】改变值啊,那么这些方法又是如何保证线程安全的呢?

新建一个对象,进行改变值的操作,把值赋给新对象即可

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

 如果想增加一个增加的方法呢?

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

    public Immutable add(int v){
        return new Immutable(this.value + v);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2038895.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【图形学】TA之路-矩阵应用平移-旋转-大小

矩阵应用&#xff1a;在 Unity 中&#xff0c;Transform 和矩阵之间的关系非常密切。Transform 组件主要用于描述和控制一个物体在三维空间中的位置、旋转和缩放&#xff0c;而这些操作背后实际上都是通过矩阵来实现的 1. Transform 组件与矩阵的关系 Transform 组件包含以下…

java简单实现双链表代码

package com.se.day03.aGenericity.eDataStructrue;/*** 自定义一个双链表的数据结构。**/public class MyDoubleList<E> {//新创建容器时&#xff0c;头部和尾部元素都是null,size0;private Node head; //头部元素private Node tail; //尾部元素private int size; // …

特殊数组Z(前缀和)

前言&#xff1a;想了好一会才想到是前缀和来写&#xff0c;并且我一开始的是从考虑这个数和这个数后面一个数&#xff0c;导致边界烦了我好久 看了一下&#xff0c;考虑这个数和这个数前一个数更好 class Solution { public:vector<bool> isArraySpecial(vector<int…

按键按下,LED 点亮,但是,理论和现象不符

通过 Debug &#xff0c;解决了一个 Bug&#xff0c;很开心&#x1f604;&#xff0c;记录下 想实现的效果&#xff1a;按下 PB12 上的按钮&#xff0c;PA7 上的 LED 点亮&#xff1b;松开&#xff0c;LED 熄灭 单片机型号&#xff1a;STM32F103C8T6 PB12 为上拉电阻&#xf…

高可用负载均衡集群

高可用负载均衡集群 相比单点的负载均衡集群&#xff0c;高可用负载均衡集群可以解决以下两个问题。 1. real server某个服务down会怎么样&#xff1f;如何解决&#xff1f; 解决 自动调用好的real server 2. scheduler server down会怎么样&#xff1f;如何解决&#xff1f…

Docker容器管理之FAQ

一、前言 某次&#xff0c;某容器服务发现无法使用了&#xff0c;查看状态为restaring状态&#xff0c;后看是云主机重启了&#xff0c;导致本地的nfs-server未自动启动&#xff0c;导致关联的集群主机&#xff0c;远程挂载点无法使用&#xff0c;影响容器服务运行。故此&#…

Qt编译错误: error: msvc-version.conf loaded but QMAKE_MSC_VER isn‘t set

方法一&#xff1a;清空构建目录 清空当前目录的多余文件即可&#xff0c;具体操作如下 一个正常的Qt项目刚被创建且没有编译时是这样的 一个main文件&#xff0c;一个pro文件&#xff0c;一个user文件&#xff0c;一个头文件(.h)&#xff0c;和一个源文件(.cpp)&#xff0c;一…

springsecurity的学习(四):实现授权

简介 springsecurity的授权&#xff0c;自定义授权失败的处理&#xff0c;跨域的处理和自定义权限校验方法的介绍 授权 权限系统作用 在后台进行用户权限的判断&#xff0c;判断当前用户是否有相应的权限&#xff0c;必须具有所需的权限才能进行相应的操作&#xff0c;以此…

高通分享:glTF 2.0扩展MPEG、3GPP在AR/VR 3D场景的沉浸式体验

日前&#xff0c;高通技术标准高级总监托马斯斯托克哈默尔&#xff08;Thomas Stockhammer&#xff09;和高通技术标准总监伊梅德布亚齐兹&#xff08;Imed Bouazizi&#xff09;撰文分享了ISO和Khronos之间是如何紧密合作&#xff0c;并最终开发出MPEG-I Scene Description IS…

基于LangChain的大模型学习手册(入门级)

前言 时间轴来到2024年的下半年&#xff0c;“大模型”这个术语&#xff0c;从几乎是ChatGPT的代名词&#xff0c;转变为AI领域一个划时代产品的广泛词汇。从单一到广泛&#xff0c;代表大模型这个世界级产品&#xff0c;正在走向枝繁叶茂的生命阶段。截止现在&#xff0c;目前…

【算法分析与设计】期末复习-小题100道

目录 0、基础知识点 一、单选题 二、多选题 三、判断题 0、基础知识点 &#xff08;1&#xff09;常见时间复杂度与公式&#xff1a; 汉诺塔&#xff1a;T(n)O(2^n) 全排列&#xff1a;T(n)O(n!) 整数划分&#xff1a; 正整数n的划分&#xff1a;p(n)q(n,n) 分治&#…

推荐系统三十六式学习笔记:工程篇.效果保证31|推荐系统的测试方法及常用指标介绍

目录 为什么要关注指标推荐系统的测试方法1.业务规则扫描2.离线模拟测试3.在线对比测试4.用户访谈 常用指标1.系统有多好&#xff1f; 假设你已经有了自己的推荐系统&#xff0c;这个系统已经上线。 为什么要关注指标 面对推荐系统这样一个有诸多复杂因素联动起作用的系统&am…

C++入门:类和对象(入门篇)

目录 前言 类的定义 1.类定义格式 2.从结构体到类的跨越 3.访问限定符 4.类域 5.类的实例化 类的默认成员函数 1.默认成员函数的定义和学习方向 2.构造函数 3.析构函数 4.拷贝构造函数 5.重载运算符 总结 疑难解答 1.this指针的用法 2.为什么拷贝构造函数的第一个参数必须…

LeetCode 热题 HOT 100 (024/100)【宇宙最简单版】

【哈希表】No. 0128 最长连续序列【中等】&#x1f449;力扣对应题目指路 希望对你有帮助呀&#xff01;&#xff01;&#x1f49c;&#x1f49c; 如有更好理解的思路&#xff0c;欢迎大家留言补充 ~ 一起加油叭 &#x1f4a6; 欢迎关注、订阅专栏 【力扣详解】谢谢你的支持&am…

WPF中RenderTransform,LayoutTransform区别

RenderTransform RenderTransform 是在渲染阶段应用的变换。它不会影响控件的布局&#xff0c;只会影响控件的外观。常用于动画和视觉效果。 • 应用时机&#xff1a;在控件已经完成布局之后。 • 影响范围&#xff1a;仅影响控件的外观&#xff0c;不影响布局。 • 常见用途&…

汇川技术|PLC应用逻辑编程技巧(2)

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01; 昨天看这块儿内容看到快十二点了&#xff0c;还没看完&#xff0c;今天接着看。 以下为学习笔记。 01 PLC程序实现状态关系 该思路编写程序的要点如下&#xff1a; ①&#xff1a;采用PLC的一个整数型变量作为状态位…

路透社中东门户媒体ZAWYA:自带流量为品牌出海赋能

路透社中东门户媒体ZAWYA:自带流量为品牌出海赋能 随着全球化的不断推进&#xff0c;越来越多的企业开始将目光投向海外市场&#xff0c;寻求更广阔的发展空间。然而&#xff0c;在激烈的市场竞争中&#xff0c;如何让自己的品牌脱颖而出成为一个亟待解决的问题。在这个背景下…

Windows 11系统SQL Server 2016 数据库安装 最新2024教程和使用

文章目录 目录 文章目录 安装流程 小结 概要安装流程技术细节小结 概要 文件可以关注作者公众号《全栈鍾猿》&#xff0c;发您 安装流程 双击运行 在资源管理器页面如图所示 点击全选-->取消勾选如图所示的3个---》点击下一步 点击下一步 安装完成&#xff0c;如图所示 &a…

USB-HUB电路设计

USB-HUB电路设计 USB-HUB电路是笔者任职电子工程师做的第一块板子,功能为USB3.0的集线器,主芯片采用RTS5411,最多能同时工作四个USB3.0设备。 由于信号有TX.RX,我们很容易将发送端和接收端搞错,毕竟从芯片出来,要经过很多的路径,如USB端子,线材,再到芯片。则芯片出来…

内网渗透—横向移动RDPWinRMWinRSSPN扫描Kerberos攻击

前言 今天仍是横向移动的内容&#xff0c;有些实验能成功&#xff0c;有些实验则各种奇怪的问题导致失败&#xff0c;这都是很常见的。就连小迪在视频中也经常翻车&#xff0c;我们只需要知道原理&#xff0c;以及如何去实现这个攻击行为即可。没必要强求所有的实验都要百分百…