线程安全性与synchronized

线程安全:多线程访问某个类时,这个类始终都能表现出正确的行为,这个类就是线程安全的。

简单的说,就是多线程执行的结果与单线程执行的结果始终一致,不会因为多线程的执行时序不同而出现不同的结果

以下是一个线程不安全的程序:

当这段代码在单线程中执行时,会得出正确的答案,而在多线程环境中,则出现了执行结果完全靠运气,结果依赖于线程之间的执行时序,显然违背了线程安全的定义:多线程访问某个类时,这个类始终都能表现出正确的行为。

为什么会出现这样的结果?

虽然count++看上去很像是一个操作,实际在执行的时候是三个独立操作:

  1. 读取count的值。

  2. 将值+1。

  3. 写入count。

当上面这一个“读取-修改-写入”的操作没有使用同步机制保证这三步操作是一个不可分割原子操作,就会出现不同线程的这三步操作交替执行。

只需要加上一些线程协调机制便可将这三步操作作为一个原子操作,比如同步锁:

以上现象有一个术语来形容,叫竞态条件,即多线程访问同一资源时,如果对资源访问顺序敏感,执行结果依赖于线程的执行顺序,则为竞态条件。

Synchronized是java内置的锁,这是一种互斥锁,只能由一个线程进入被锁保护的代码,因此这个锁保护的代码块以原子方式执行,可以提供对象锁/类锁/安全发布全局变量的功能,

Synchronized的几种用法:

1.****对象锁:

2.****类锁:

使用锁时需要注意的地方:

  1. 当需要锁来协调线程对某个变量的访问时,所有访问这个变量的位置需要用同一个锁。

2.使用锁时要清楚代码块的代码是否需要执行很长时间,比如网络和IO操作,如果长时间持有锁,会造成线程竞争,等待的线程有两种等待策略:

a.忙锁:自旋等待锁释放,适合代码块执行时间很短的情况。

b.闲锁:将等待的线程挂起,锁释放后在合适的时机上下文切换,有一定内存同步代价。

jvm会对synchronized代码块进行不同程度的锁膨胀,偏向锁、轻量级锁、重量级锁,这个在后面的jvm系列博文会总结到。

当代码块执行的任务需要很长时间时尽量不要加锁。

同步代码块应尽可能短小,不需要同步的代码尽量移出,代码越短小,执行时间越短,线程竞争就越少,性能和吞吐量会更好,简单说就是快进快出

一些优化synchronized互斥锁性能的方法:

  1. 分段锁。

  2. 读写锁。

线程封闭

1. ad-hoc封闭:维护线程封闭性的职责完全由程序来承担。

例如代码中不做任何同步处理,只是把线程不安全的程序做成单线程程序,只有一个线程来执行了,自然就不会存在什么竞态条件、资源竞争,不推荐使用,建议用ThreadLocal。

在volatile变量上存在一种特殊的线程封闭。只要你能确保只有单个线程对共享的volatile变量执行写入操作,那么就可以安全地在这些共享的volatile变量上执行"读取—修改—写入"的操作。这种情况下相当于将修改操作封闭在单个线程中以防止发生竞态条件,并且volatile的可见性还确保其他的线程能看到最新的值。

  1. 栈封闭

简单说就是不用全局变量,用局部变量,方法内部声明的局部变量作用域是封闭在单个线程里的,不对其它线程共享,自然就不会出现竞态条件。



为什么栈封闭的局部变量能保证线程安全呢?后面更新的JVM系列会说明运行过程中的栈帧结构。

3. ThreadLocal

是一种更规范的维护线程封闭性的方式,使变量和持有变量的线程关联起来,每个变量都有一份自己的变量,相互隔离防止共享。

例如实现线程与用户信息的绑定:

不可变对象,不能修改,只读共享

不可变的成员变量不需要额外同步,天生线程安全,如果该成员变量是一个对象,则所有属性都需要声明为final保证不可变性。

如图static保证了jvm安全发布该变量,发布后对该类创建的所有线程都是可见的,final保证了发布后为只读,不可写。

当多线程程序存在线程安全问题时,选择解决方法的优先级应当如下:

1.能否做成无状态的不变对象。无状态是最安全的。

2.能否线程封闭。

3.采用何种同步技术。

线程安全与synchronized的更多相关文章

  1. Java线程同步(synchronized)——卖票问题

    卖票问题通常被用来举例说明线程同步问题,在Java中,采用关键字synchronized关键字来解决线程同步的问题. Java任意类型的对象都有一个标志位,该标志位具有0,1两种状态,其开始状态为1, ...

  2. 线程池 队列 synchronized

    线程池 BlockingQueue synchronized volatile 本章从线程池到阻塞队列BlockingQueue.从BlockingQueue到synchronized 和 volat ...

  3. Java线程锁,synchronized、wait、notify详解

    (原) JAVA多线程这一块有点绕,特别是对于锁,对锁机制理解不清的话,程序出现了问题也很难找到原因,在此记录一下线程的执行以及各种锁. 1.JAVA中,每个对象有且只有一把锁(lock),也叫监视器 ...

  4. 从线程池到synchronized关键字详解

    线程池 BlockingQueue synchronized volatile 前段时间看了一篇关于"一名3年工作经验的程序员应该具备的技能"文章,倍受打击.很多熟悉而又陌生的知识 ...

  5. java线程学习之synchronized关键字

    关键字synchronized的作用是实现线程间的同步.它的任务是对同步的代码加锁.一个代码块同时只能有同一个线程进行读和写操作,从而保证线程间是安全的. 线程安全的概念是:当多个线程访问某一个类(对 ...

  6. [多线程] 线程中的synchronized关键字锁

    为什么要用锁? 在多线程中,难免会出现在多个线程中对同一个对象的实例变量或者全局静态变量进行并发访问的情况,如果不做正确的同步处理,那么产生的后果就是"脏读",也就是取到的数据其实 ...

  7. Java基础-多线程-③线程同步之synchronized

    使用线程同步解决多线程安全问题 上一篇 Java基础-多线程-②多线程的安全问题 中我们说到多线程可能引发的安全问题,原因在于多个线程共享了数据,且一个线程在操作(多为写操作)数据的过程中,另一个线程 ...

  8. java高并发系列 - 第10天:线程安全和synchronized关键字

    这是并发系列第10篇文章. 什么是线程安全? 当多个线程去访问同一个类(对象或方法)的时候,该类都能表现出正常的行为(与自己预想的结果一致),那我们就可以所这个类是线程安全的. 看一段代码: pack ...

  9. 线程安全之 synchronized 和 ReentrantLock

    线程安全之 synchronized 和 ReentrantLock + 面试题 前面我们介绍了很多关于多线程的内容,在多线程中有一个很重要的课题需要我们攻克,那就是线程安全问题.线程安全问题指的是在 ...

随机推荐

  1. vscode环境配置(三)——解决控制台终端中文输出乱码

    由于系统终端默认编码为GBK,所以需要修改为UTF-8 方法一 打开cmd输入chcp查看编码格式,查看以及修改如下图所示: 方法二

  2. Java并发编程volatile关键字

    volatile理解 Java语言是支持多线程的,为了解决线程并发的问题,在语言内部引入了 同步块 和volatile 关键字机制.volatile具有synchronized关键字的“可见性”,vo ...

  3. dom4j——使用dom4j生成xml

    使用org.dom4j.Element 创建xml /** * 生成Service.xml文件 * @param tran 交易对象 * @param filePath 文件夹路径 */ public ...

  4. Msql 给结果拼接字符串

    SELECT CONCAT("内容:",info)AS info FROM 表名;

  5. 人工智能中小样本问题相关的系列模型演变及学习笔记(二):生成对抗网络 GAN

    [说在前面]本人博客新手一枚,象牙塔的老白,职业场的小白.以下内容仅为个人见解,欢迎批评指正,不喜勿喷![握手][握手] [再啰嗦一下]本文衔接上一个随笔:人工智能中小样本问题相关的系列模型演变及学习 ...

  6. StreamSets使用指南

    StreamSets使用指南 最近在调研Streamsets,照猫画虎做了几个最简单的Demo鉴于网络上相关资料非常少,做个记录. 1.简介 Streamsets是一款大数据实时采集和ETL工具,可以 ...

  7. Kivy中显示汉字的问题

    1. kivy中显示中文乱码和提示错误的原因: 编码问题 字体问题 2. 字体问题的解决 可以下载支持中文的字体文件ttf,我这里使用了微软雅黑中文简体msyh.ttf.我们在编写布局时可以直接在相关 ...

  8. [json-server] RESTful API 中,取主数据时,同时获取多个关联子表的数据

    项目背景: back-end:ASP.NET Core WebAPI front-end:Vue(+vue-router +vuex +axios)(webpack)(json-server + mo ...

  9. 【Ubuntu】安装Ubuntu18.04.2LTS

    环境:win10专业版.联想30D9主板 ubuntu:18.04.2LTS:Ubuntu镜像传送门:https://ubuntu.com/download/desktop 有两块硬盘,win10安装 ...

  10. matlab自学笔记

    1.字符串格式化,用sprintf如a=sprintf('%.2f_除以%d等于%.3f',1.5,2,0.75)%则a=1.50除以2等于0.750 2.for循环只能针对整数,不能遍历字符串或其他 ...