Java 并发基础——线程安全性

线程安全:多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协调,这个类都能表现出正确的行为,那么久称这个类是线程安全的。

在线程安全类中封装了必要的同步机制,因此客户端无需采取进一步的同步措施。

原子性


要么不执行,要么执行到底。原子性就是当某一个线程修改i的值的时候,从取出i到将新的i的值写给i之间不能有其他线程对i进行任何操作。也就是说保证某个线程对i的操作是原子性的,这样就可以避免数据脏读。 通过锁机制或者CAS(Compare And Set 需要硬件CPU的支持)操作可以保证操作的原子性。

当多个线程访问某个状态变量,并且其中有一个线程执行写入操作时,必须采用同步机制来协调这些线程对变量的访问。无状态对象一定是线程安全的。

  如果我们在无状态的对象中增加一个状态时,会出现什么情况呢?假设我们按照以下方式在servlet中增加一个"命中计数器"来管理请求数量:在servlet中增加一个long类型的域,每处理一个请求就在这个值上加1。

public class UnsafeCountingFactorizer implements Servlet {
private long count = 0;

public long getCount() {
return count ;
}

@Override
public void service(ServletRequest arg0, ServletResponse arg1)
throws ServletException, IOException {
// do something
count++;
}
}

不幸的是,以上代码不是线程安全的,因为count++并非是原子操作,实际上,它包含了三个独立的操作:读取count的值,将值加1,然后将计算结果写入count。如果线程A读到count为10,马上线程B读到count也为10,线程A加1写入后为11,线程B由于已经读过count值为10,执行加1写入后依然为11,这样就丢失了一次计数。

        在 count++例子中线程不安全是因为 count++并非原子操作,我们可以使用原子类,确保确保操作是原子,这样这个类就是线程安全的了。

public class CountingFactorizer implements Servlet {
private final AtomicLong count = new AtomicLong(0);

public long getCount() {
return count .get() ;
}

@Override
public void service(ServletRequest arg0, ServletResponse arg1)
throws ServletException, IOException {
// do something
count.incrementAndGet();
}
}

 

       AtomicLong是java.util.concurrent.atomic包中的原子变量类,它能够实现原子的自增操作,这样就是线程安全的了。   同样,上述情况还会出现在 单例模式的懒加载过程中,当多个线程同时访问 getInstance()函数时。这篇文章中有讲解:实现优雅的单例模式

加锁机制


      线程在执行被synchronized修饰的代码块时,首先检查是否有其他线程持有该锁,如果有则阻塞等待,如果没有则持有该锁,并在执行完之后释放该锁。

      除了使用原子变量的方式外,我们也可以通过加锁的方式实现线程安全性。还是UnsafeCountingFactorizer,我们只要在它的service方法上增加synchronized关键字,那么它就是线程安全的了。当然在整个方法中加锁在这里是效率很低的,因为我们只需要保证count++操作的原子性,所以这里只对count++进行了加锁,代码如下:

 

public class UnsafeCountingFactorizer implements Servlet {private long count = 0;public long getCount() {return count ;}@Overridepublic void service(ServletRequest arg0, ServletResponse arg1)throws ServletException, IOException {// do somethingsynchronized(this){count++;}}
}

 

Synchronized代码块使得一段程序的执行具有 原子性,即每个时刻只能有一个线程持有这个代码块,多个线程执行在执行时会互不干扰。

java 内存模型及 可见性


     Java的内存模型没有上面这么简单,在Java Memory Model中,Memory分为两类,main memory和working memory,main memory为所有线程共享,working memory中存放的是线程所需要的变量的拷贝(线程要对main memory中的内容进行操作的话,首先需要拷贝到自己的working memory,一般为了速度,working memory一般是在cpu的cache中的)。被volatile修饰的变量在被操作的时候不会产生working memory的拷贝,而是直接操作main memory,当然volatile虽然解决了变量的可见性问题,但没有解决变量操作的原子性的问题,这个还需要synchronized或者CAS相关操作配合进行。

每个线程内部都保有共享变量的副本,当一个线程更新了这个共享变量,另一个线程可能看的到,可能看不到,这就是可见性问题。

下面这段代码中 main 线程中 改变了 ready的值,当开启多个子线程时,子线程的值并不是马上就刷新为最新的ready的值(这里的中间刷新的时间间隔到底是多长,或者子线程的刷新机制,自己也不太清楚。当开启一个线程去执行时,ready值改变时就会立刻刷新,循环立刻就结束,但是当开启多个线程时,就会有一定的延迟)。

 

public class SelfTest {private  static boolean ready;private static int number;private static long time;public static class ReadThread extends Thread {public void run() {while(!ready ){System. out.println("*******  "+Thread.currentThread()+""+number);Thread. yield();}System. out.println(number+"   currentThread: "+Thread.currentThread());}}public static void main(String [] args) {time = System.currentTimeMillis();new ReadThread().start();new ReadThread().start();new ReadThread().start();new ReadThread().start();try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}number = 42;ready = true ;System.out.println("赋值时间:ready = true     ");}
}

 

上面这段代码的执行结果:可以看出赋值后,循环还是执行了几次。

image

此时如果把 ready的属性加上 volatile 结果便是如下的效果:

image

由此可见Volatile可以解决内存可见性的问题。

上面讲的加锁机制同样可以解决内存可见性的问题,加锁的含义不仅仅局限于互斥行为,还包括内存可见性。为了确保所有线程都能看到共享变量的最新值,所有执行读操作或者写操作的线程都必须在同一个锁上同步。

注:由于System.out.println的执行仍然需要时间,所以这面打印的顺序还是可能出现错乱。

参考:

http://www.mamicode.com/info-detail-245652.html

并发编程实战

http://www.cnblogs.com/NeilZhang/p/7979629.html

梦想不是浮躁,而是沉淀和积累

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

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

相关文章

详解一阶段3D物体检测网络 SE-SSD: Self-Ensembling Single-Stage Object Detector From Point Cloud

本文介绍一篇一阶段的3D物体检测网络:SE-SSD,论文已收录于 CVPR 2021。 这里重点是理解本文提出的 Consistency Loss 、Orientation-Aware Distance-IoU Loss、Shape-Aware Data Augmentation。 论文链接为:https://arxiv.org/pdf/2104.0980…

详解3D点云分割网络 Cylindrical and Asymmetrical 3D Convolution Networksfor LiDAR Segmentation

本文介绍一篇3D点云分割网络:Cylinder3D,论文已收录于 CVPR 2021。 这里重点是理解本文提出的 Cylindrical Partition 和 Asymmetrical 3D Convolution Network。 论文链接为:https://arxiv.org/pdf/2011.10033.pdf 项目链接为:…

自动驾驶3D物体检测研究综述 3D Object Detection for Autonomous Driving: A Survey

本文介绍一篇最新的自动驾驶3D物体检测研究综述(2021年6月份发布),来源于中国人民大学,论文共26页,99篇参考文献。 论文链接为:https://arxiv.org/pdf/2106.10823.pdf 0. Abstract 自动驾驶被看作是避免人…

Java中接口的多继承

我们知道Java的类只能继承一个类,但可以实现多个接口。但是你知道么?Java中的接口却可以继承多个接口。本文就来说一说Java中接口的多继承。 进入主题之前,先扩展一下。Java为什么只支持单继承呢? 我们不妨假设Java支持多继承&a…

详解基于IMU/GPS的行人定位: IMU/GPS Based Pedestrian Localization

本文介绍一篇使用 IMU/GPS 数据融合的行人定位论文,这里重点是理解本文提出的 Stop Detection 和 GPS Correction。 论文地址为:https://www.researchgate.net/publication/261452498_IMUGPS_based_pedestrian_localization 1. Introduction 低成本的 …

每次maven刷新jdk都要重新设置

pom.xml <java.version>17</java.version> 改为<java.version>1.8</java.version>

【CodeForces - 706D】Vasiliy's Multiset(01字典树)

题干&#xff1a; Author has gone out of the stories about Vasiliy, so here is just a formal task description. You are given q queries and a multiset A, initially containing only integer 0. There are three types of queries: " x" — add integer …

详解自动驾驶仿真框架OpenCDA: An Open Cooperative Driving Automation Framework Integrated with Co-Simulation

本文介绍一款同时支持协同驾驶开发与测试、自动驾驶全栈开发 和 CARLA-SUMO联合仿真的开源框架 OpenCDA&#xff0c;论文已收录于 ITSC 2021。主要feature有&#xff1a; 支持CARLA-SUMO联合仿真&#xff0c;CARLA端主管环境渲染、传感器模拟、车辆动力&#xff0c;Sumo端主管…

JavaMonitor 监视器

为什么wait(), notify()和notifyAll()必须在同步方法或者同步块中被调用&#xff1f; 当一个线程需要调用对象的wait()方法的时候&#xff0c;这个线程必须拥有该对象的锁&#xff0c;接着它就会释放这个对象锁并进入等待状态直到其他线程调用这个对象上的notify()方法。同样的…

KITTI自动驾驶数据集可视化教程

本文介绍关于自动驾驶数据集KITTI的基本操作&#xff0c;包括Camera和LiDAR可视化教程&#xff0c;源码已上传&#xff1a;https://download.csdn.net/download/cg129054036/20907604 1. 数据准备 将 KITTI 数据 (calib, image_2, label_2, velodyne) 添加到 dataset/KITTI/ob…

重读经典《Quaternion kinematics for the error-state Kalman filter》

本文将介绍一篇关于 四元数运动学的误差卡尔曼滤波 经典论文。本文结构如下&#xff1a; 第1章四元数定义和性质介绍&#xff0c;包括&#xff1a;加法、减法、乘法&#xff08;矩阵表示&#xff09;、模、幂数、指数运算等。第2章旋转群定义和性质介绍&#xff0c;包括&#…

【CodeForces - 789C】Functions again(最大子段和变形,dp,思维)

题干&#xff1a; Something happened in Uzhlyandia again... There are riots on the streets... Famous Uzhlyandian superheroes Shean the Sheep and Stas the Giraffe were called in order to save the situation. Upon the arriving, they found that citizens are wo…

一步步编写操作系统 55 CPL和DPL入门2

接上节。 图中第132行的jmp指令&#xff0c;段选择子为SELECTOR_CODE&#xff0c;其RPL的值为RPL0&#xff0c;RPL0定义在include/boot.inc中&#xff0c;其值为0。选择子的索引部分值为1&#xff0c;表示对应GDT中第1个段描述符&#xff0c;该描述符的DPL为0&#xff0c;&…

详解停车位检测算法 Vision-Based Parking-Slot Detection: A DCNN-Based Approach and a Large-Scale Benchmark

本文介绍一篇基于深度学习的停车位检测论文&#xff1a;DeepPS&#xff0c;作者同时公开了数据集ps2.0&#xff0c;工作很扎实&#xff0c;对于入门停车位检测很有帮助&#xff0c;论文发表在 IEEE T-IP 2018。 项目链接为&#xff1a;https://cslinzhang.github.io/deepps/ 0…

Monitor(管程)是什么意思?Java中Monitor(管程)的介绍

本篇文章给大家带来的内容是关于Monitor&#xff08;管程&#xff09;是什么意思&#xff1f;Java中Monitor&#xff08;管程&#xff09;的介绍&#xff0c;有一定的参考价值&#xff0c;有需要的朋友可以参考一下&#xff0c;希望对你有所帮助。 monitor的概念 管程&#x…

详解经典GPS辅助惯性导航论文 A GPS-aided Inertial Navigation System in Direct Configuration

本文介绍一篇 IMU 和 GPS 融合的惯性导航论文&#xff0c;重点是理解本文提出的&#xff1a;Dynamical constraints update、Roll and pitch updates 和 Position and heading updates。 论文链接为&#xff1a;https://www.sciencedirect.com/science/article/pii/S166564231…

详解停车位检测论文:Attentional Graph Neural Network for Parking-slot Detection

本文介绍一篇注意力图神经网络用于停车位检测论文&#xff0c;论文已收录于 RA-L2021。在之前的基于卷积神经网络的停车位检测方法中&#xff0c;很少考虑停车位标记点之间的关联信息&#xff0c;从而导致需要复杂的后处理。在本文中&#xff0c;作者将环视图中的标记点看作图结…

详解3D物体检测模型 SPG: Unsupervised Domain Adaptation for 3D Object Detection via Semantic Point Generation

本文对基于激光雷达的无监督域自适应3D物体检测进行了研究&#xff0c;论文已收录于 ICCV2021。 在Waymo Domain Adaptation dataset上&#xff0c;作者发现点云质量的下降是3D物件检测器性能下降的主要原因。因此论文提出了Semantic Point Generation (SPG)方法&#xff0c;首…

Waymo研发经理:《自动驾驶感知前沿技术介绍》

Waymo研发经理|自动驾驶感知前沿技术介绍这是Waymo研发经理&#xff08;VoxelNet作者&#xff09;的一个最新分享报告&#xff1a;《自动驾驶感知前沿技术介绍》。在这份报告里&#xff0c;介绍了Waymo在自动驾驶感知中五个研究方向的最新成果。 1. Overview of the autonomous…

几种常见软件过程模型的比较

瀑布模型 瀑布模型&#xff08;经典生命周期&#xff09;提出了软件开发的系统化的、顺序的方法。其流 程从用户需求规格说明开始&#xff0c;通过策划、建模、构建和部署的过程&#xff0c;最终提供一 个完整的软件并提供持续的技术支持。 优点&#xff1a; 1. 强调开发的…