java多线程初探(二)构建线程安全类

java多线程——线程安全-举例 之所以会输出8、9、7,是因为进程内的所有线程都可以访问到该区域,当第一个线程已经获得9这个数了,还没来得及输出,下一个线程在这段时间的空隙获得了8这个值,故输出时会输出8、9的顺序值。线程安全性的一个重要方面是确保对共享资源的访问是原子的,即不可分割的,要么全部完成,要么全部不完成。如果忽略了线程安全性,可能会导致难以调试和重现的错误,这些错误可能只在特定的线程调度或系统负载下才会出现。因此,开发者需要仔细考虑并设计线程安全的代码,使用适当的同步机制,并对共享资源进行适当的访问控制。 阅读详情

上一篇记录了多线程的简单使用,这里接着记录。

一、可见性

可见性:读操作和写操作在两个线程时,不能保证读操作可以实时的看到其他线程写入的值,如果能保证则说拥有可见性

保证可见性方法:

1,当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值(而不是高速缓存中)。

2,通过synchronized和Lock也能够保证可见性,synchronized和Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存当中。

对可见性,笔者测试代码如下:

package gcc.thread.test;

/**
 * Created by gcc on 2018/3/29.
 */
public class NoVisibility {

    private static boolean readFlag;//默认false
    private static int count=0;

    public static void main(String[] args) {
        ReadThread read1 = new ReadThread();
        Thread thread = new Thread(read1);
        Thread thread2 = new Thread(read1);
        Thread thread3 = new Thread(read1);
        thread.start();
        thread2.start();
        thread3.start();
        count=50;
        readFlag=true;
        System.out.println("main--count:"+count);
    }

    private static class ReadThread implements Runnable{
        public void run(){
            System.out.println("ReadThread1--count:"+Thread.currentThread().getName()+"--"+count);
            while (!readFlag){
                Thread.yield();//使当前线程从执行状态(运行状态)变为可执行态(就绪状态)。此线程会把自己CPU执行的时间让掉,让自己或者其它的线程运行(重新竞争)
            }
            System.out.println("ReadThread2--count:"+Thread.currentThread().getName()+"--"+count);
        }
    }
}

结果如下:

ReadThread1--count:Thread-0--0
ReadThread1--count:Thread-2--50
ReadThread2--count:Thread-2--50
main--count:50
ReadThread1--count:Thread-1--0
ReadThread2--count:Thread-1--50
ReadThread2--count:Thread-0--50

这里有两类线程,主线程和读线程,主线程开启了三个读线程,读线程获取共享数据count,可以看到主线程应该先写入的count=50,有可能在读线程里没有被读到,结果就为0。这就引发了可见和不可见的问题。

二、有序性

有序性:即程序执行的顺序按照代码的先后顺序执行。举个简单的例子,看下面这段代码:

int i = 0;              
boolean flag = false;
i = 1;                //语句1  

flag = true;          //语句2

从代码顺序上看,语句1是在语句2前面的,那么JVM在真正执行这段代码的时候会保证语句1一定会在语句2前面执行吗?不一定,为什么呢?这里可能会发生指令重排序(Instruction Reorder)。

指令重排序:一般来说,处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的。

处理器在进行重排序时是会考虑指令之间的数据依赖性,如果一个指令2必须用到指令1的结果,那么处理器会保证指令1会在指令2之前执行。

多线程时重排序:

//线程1:
context = loadContext();   //语句1
inited = true;             //语句2
 
//线程2:
while(!inited ){
  sleep()
}

doSomethingwithconfig(context);

上面代码中,由于语句1和语句2没有数据依赖性,因此可能会被重排序。假如发生了重排序,在线程1执行过程中先执行语句2,而此时线程2会以为初始化工作已经完成,那么就会跳出while循环,去执行doSomethingwithconfig(context)方法,而此时context并没有被线程1初始化,就会导致程序出错。

注:要想并发程序正确地执行,必须保证原子性、可见性以及有序性。只要有一个没有被保证,就可能导致程序运行不正确。

三、线程封闭

这里记录下线程封闭的常用方法ThreadLocal。

线程封闭就是将共享的可变数据,封闭在一个线程内,即在单线程内访问数据,这样不用同步也是安全的。

ThreadLocal,线程本地变量,是一种特殊的线程绑定机制,将变量与线程绑定在一起,为每一个线程维护一个独立的变量副本,通过ThreadLocal可以将对象的可见范围限制在同一个线程内。

ThreadLocal可以理解为将对象的作用范围限制在一个线程上下文中,使得变量的作用域为“线程级”。

例如:

public final static ThreadLocal<String> RESOURCE = new ThreadLocal<String>();


Java实现HTTP协议断点续传的多线程与线程安全实践 本文还有配套的精品资源,点击获取 简介:Java多线程和线程安全是构建高效并发应用程序的关键,本实践将深入探讨如何在Java中实现基于HTTP协议的断点续传功能,该功能在大文件下载和网络传输中非常实用。我们将学习线程的基础知识,包括线程的创建与管理、线程同步和HTTP协议的断点续传机制,并通过实践提升对这些概念的理解和应用能力。 1. Java中线程的概念与管理 ... 阅读详情

相关推荐

华为云CodeHub代码托管

什么是代码托管 代码托管(CodeHub)是面向软件开发者的基于Git的在线代码托管服务,是具备安全管控、成员/权限管理、分支保护/合并、在线编辑、统计服务等功能的云端代码仓库,旨在解决软件开发者在跨地域协同、多分支并发、代码版本管理、安全性等方面的问题。 代码托管具有以下特性 · 在线代码阅读、修改、提交,随时随地开发,不受地域限制。 · 在线分支管理,包含分支新建、切换、合并,实现多分支并行开发,效率高。 master分支:最为稳定,功能比较完整,随时可发布的代码。 develop分支:用于平时开

LUJINYUANA的博客 1万+

入侵检测模型(An Intrusion-Detection Model)

入侵检测

一智哇的博客 3894

Frida实战:SSL Pinning绕过技术全解析

本文详细解析了如何使用Frida工具绕过SSL Pinning技术,包括环境搭建、四种实战绕过方案及常见问题排查指南。通过具体代码示例和实战经验,帮助安全研究人员快速掌握SSL Pinning绕过技术,适用于金融类App的安全测试场景。

weixin_42530732的博客 188

JavaSE---(Java多线程)

Java多线程 简介 普通方法调用和多线程区别 进程和线程 程序: 程序是指令和数据的集合。是一个静态的概念。 进程: 指程序的一次执行过程,是一个动态的概念。【进程是系统资源分配的单位】 一个进程可以有多个线程,如: 视频中同时听声音,看图像,看弹幕等。 一个进程至少包含一个线程,不然没有存在的意义。 【线程是CPU调度和执行的单位】 注意: 1.此处的多线程是模拟出来的多线程。 模拟多线程即在一个CPU的情况下,在同一个时间点,cpu只能执行一个线程, 因为线程切换的很快,所有就有同

Carson's Blog 1023

Silvaco Atlas从头开始(四)——定义材料参数和模型

这部分是关于定义材料参数和模型。

qsz1425AWD2121的博客 4650

【交易系统系列27】带你看懂订单的“奇幻漂流”

作为一个在交易所后台“厨房”里摸爬滚打了十多年的老兵,我将用一杯手冲咖啡的时间,带你亲历一次完整的订单“奇幻漂流”。本文将用一个“奶爸”的生活视角,硬核拆解**撮合(Matching)**、**清算(Clearing)**、**结算(Settlement)**和**出入金**这四大核心环节。这不仅是一次对**交易系统优化**和**撮合引擎架构**的深度剖析,更是一场关于传统金融与数字金融两种不同“上菜”哲学的真实故事。

weixin_43988453的博客 407

多线程(学习笔记)

01多线程的概述 02多线程的实现方式1 代码 首先创建一个线程类 public class MyThread extends Thread{ @Override public void run() { for (int i = 0; i < 30; i++) { System.out.println(getName()+":"+i); } } } 接下...

漫漫路上人的博客 343

从零开始!在 Windows 上安装与配置 Dify

这篇博客将详细介绍如何在 Windows 系统上部署 Dify,适合零基础用户。从 Docker 和 WSL 的安装配置开始,逐步指导用户设置 Git、Docker 环境以及 Dify 配置文件,解决可能遇到的端口冲突等问题,最终完成 Dify 的启动和测试。通过简明易懂的步骤,帮助用户在本地成功运行 Dify,实现模型供应商配置,让 Dify 项目在 Windows 平台上顺利上线。

qq_49035156的博客 5万+

构建线程安全的类

1、因为对象的状态由对象的变量组成,通常叫做域{x,y...}, 通过private final构建一个封闭的环境,变量的访问通过对外的方法接口,这个方法接口是同步的,这样就能够保证对象的线程安全。 2、通过final定义可以缩减对象的域。 3、通过对象的私有锁来保护状态 public class privateLock{ private final Object  myLock = ne

张少飞的优快云 344

PS2硬盘启动终极指南:从FMCB到OPL,告别光驱打造游戏博物馆

在计算机存储与数据读取领域,硬盘启动技术通过将操作系统或应用程序从本地硬盘直接加载,绕过了传统光驱等外部介质,实现了速度与可靠性的双重提升。其核心原理在于利用引导程序接管系统初始化流程,直接访问硬盘上的特定分区与文件镜像。这项技术的价值在于极大提升了数据读取效率、降低了物理介质损耗,并扩展了存储容量与管理的灵活性。在怀旧游戏硬件改造、嵌入式系统定制等场景中,硬盘启动技术被广泛应用,以实现老旧设备的功能焕新与性能优化。本文聚焦于索尼PS2游戏主机的硬盘启动方案,深入探讨了如何利用FMCB(Free MCBoo

weixin_34295316的博客 1777

10、边缘智能学习技术解析

本文深入解析了边缘智能学习技术的四大核心方法:联邦学习、DNN拆分、迁移学习和八卦学习。文章从人类大脑的学习机制出发,引出边缘级智能的重要性,并详细阐述各类技术的架构、优势、挑战及适用场景。通过对比分析,展示了不同技术在隐私性、效率、可扩展性等方面的特性,并探讨了未来融合多种技术、软硬件协同优化及应用领域拓展的发展趋势,为边缘智能在物联网与人工智能领域的应用提供了系统性参考。

ppp33的博客 117

Java集合中那些类是线程安全的

线程安全类 在集合框架中,有些类是线程安全的,这些都是jdk1.1中的出现的。在jdk1.2之后,就出现许许多多非线程安全的类。 下面是这些线程安全的同步的类: vector:就比arraylist多了个同步化机制(线程安全),因为效率较低,现在已经不太建议使用。在web应用中,特别是前台页面,往往效率(页面响应速度)是优先考虑的。 statck:堆栈类,先进后出 hashtable:就比

Mexican的博客 10万+

OpenCV-Python实战(3)——OpenCV中绘制图形与文本

OpenCV 是一个的跨平台计算机视觉库,实现了图像处理和计算机视觉方面的很多通用算法。本文介绍了 OpenCV 提供的与绘制图形和文本相关的函数。在图形方面,我们了解了如何绘制基本图形(直线、矩形和圆形等)以及高级图形(剪裁线、箭头、椭圆和多边形)。在文本方面,我们了解了如何绘制文本以及 OpenCV 库中的所有可用字体。

盼小辉丶的博客 2万+

Java多线程之线程安全问题

Java多线程中的线程安全问题, 解决方法, 线程安全和不安全的标准类.

trong_ 的烂笔头 7225

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

java线程安全类

java线程安全类介绍

heat3_6的博客 1420

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

多线程——线程安全的集合类

介绍了这么多关于多线程相关的知识后,在我们 Java 中哪些集合类在使用的时候是线程安全的呢?其实,我们了解的集合类大部分都是线程不安全的,像 HashMap、ArrayList……,那么本篇文章就来介绍一下哪些集合类是线程安全的,它们又是如何保证线程安全的。

HKJ_numb1的博客 2120

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Java 多线程编程中如何保证线程安全?

线程安全是指在多线程环境下,对共享资源的访问和操作不会导致数据不一致、程序崩溃或其他不可预期的结果。也就是说,多个线程同时访问和修改共享资源时,程序的行为仍然符合预期,如同单线程环境下执行一样。例如,一个计数器类在单线程环境下可以正常工作,但在多线程环境中,如果多个线程同时对计数器进行自增操作,可能会出现计数不准确的问题,而线程安全的计数器类则能避免这种情况。这些类使用 CAS(Compare-And-Swap)算法实现,能够在不使用锁的情况下保证对共享变量的原子操作。实现线程安全的方法:使用同步机制。

qq_45626589的博客 1382

JAVA多线程之初探List线程安全的三种实现方式

初探List线程安全的三种实现方式 先演示一下List线程不安全的情况 package JUC.unsafe; import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.concurrent.CopyOnWriteArrayList; /** * ArrayList线程...

千里之行,始于足下 2583

多线程:Vector是线程安全的吗

线程安全,在java的多并发编程中是重要概念,意思是,多个线程同时操作一个对象,在各种不同情况下,都不会造成不同的后果。 一个经典问题,Vector到底是不是线程安全的?   很多人都会回答,是,vector是线程安全的。 诚然,不止是很多IT教材上是这么写的,就连JDK的作者写的注释也是这么说的。如下图(图为 JDK中Vector的源代码):注释中,红框标记的部分写着:如果你不需要线程安...

五山口老法师 3787

Java多线程二-线程安全

多个线程,同时操作同一个共享资源的时候,可能会出现业务安全问题。

qq_19343089的博客 1082

多线程的创建、Thread类、线程安全、同步、通信

多线程的创建 方式一:继承Thread类 方式二:实现Runnable接口 方式三:JDK 5.0新增:实现Callable接口 Thread的常用方法 线程安全 线程安全问题是什么、发生的原因 线程安全问题案例模拟 线程同步 同步思想概述 方式一:同步代码块 方式二:同步方法 方式三:Lock锁 线程通信【了解】 线程池【重点】 线程池概述 线程池实现的API、参数说明 线程池处理Runnable任务 线程池处理Callable任务 Executors工具类实现线程池 定时器 并发、并行 线程的生命周期

weixin_52270382的博客 3212

4.Java加强-多线程的实现-Thread类-线程安全

【代码】4.Java加强-多线程的实现-Thread类-线程安全。

weixin_45286894的博客 939

java多线程编程(二)一一>线程安全问题, 单例模式, 解决程线程安全问题的措施

如果多线程环境下代码运行的结果是符合我们预期的,即在单线程环境应该的结果,则说这个程序是线程安全的。

robin_suli的博客 1538

[线程]JUC中常见的类 及 集合类在多线程下的线程安全问题

下面介绍的内容是面试中常考, 但是实际开发中用不到的知识。

m0_73992740的博客 1092

java多线程会造成线程安全问题的原因总结

众所周知,多线程会造成线程安全问题,那么多线程为什么会导致线程安全问题呢? 一:首先了解jvm内存的运行时数据区 1.堆区:存储对象实例(和实例变量),数组等 2.java虚拟机栈(方法·栈),存放方法声明,局部变量,对象的引用变量,基本数据类型变量等 3.本地方法栈:存储一些本地方法(native关键字修饰的方法,如hashCode()方法,clone方法,Thread类的star0()方法) 4.方法区:存储类元数据,常量,静态变...

m0_57713282的博客 5184
上一篇: java8类库简单了解(二)Math
下一篇: java多线程初探(三)并发容器
gcc_front
博客等级 码龄9年 16粉丝 98原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值