多线程安全问题2

1.volatile关键字

<1>作用:强制线程每次在使用的时候,都会看一下共享区域最新的值[用于提供线程安全]

<2>与synchronized的区别和联系:
把代码块声明为 synchronized,有两个重要后果,通常是指该代码具有 原子性(atomicity)和 可见性(visibility);
volatile变量具有 synchronized 的可见性特性,但是不具备原子性。这就是说线程能够自动发现 volatile 变量的最新值
<3>使用条件
您只能在有限的一些情形下使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:
a.对变量的写操作不依赖于当前值。
b.该变量没有包含在具有其他变量的不变式中

注:【单独使用 volatile 还不足以实现计数器、互斥锁或任何具有与多个变量相关的不变式的类(例如 “start <=end”)】

<4>实现场景【结婚基金问题】

//volatile关键字:强制线程每次在使用的时候,都会看一下共享区域最新的值
public class Demo1 {public static void main(String[] args) {//结婚基金问题Girl girl = new Girl();Boy boy = new Boy();girl.start();boy.start();}
}//Boy类
public class Boy extends Thread {@Overridepublic void run() {try {Thread.sleep(10);Money.money = 90000;} catch (InterruptedException e) {e.printStackTrace();}}
}//Girl类
public class Girl extends Thread{@Overridepublic void run() {while (true){while (Money.money==100000){}System.out.println("基金不是十万了");break;}}
}//Money
public class Money {//1.volatile关键字:强制线程每次在使用的时候,都会看一下共享区域最新的值public static volatile int money=100000;//2.同步代码块/*public static  int money=100000;public static final Object lock =new Object();*/
}打印结果:
--------------------------------------------------------------------------------
基金不是十万了
2.AtomicInteger[原子类]的原子性

<1>概念
原子性指意思是多个操作是不可分割的原子项,他们要么同时成功,要么同时失败
<2>原理
主内存【堆】,线程本地内存【栈】
自增操作,count++为例,其实底层是要完成三个步骤(这三个步骤是不可分割的)
1.从主内存拷贝一个变量副本到线程本地内存
2.对变量副本进行操作
3.把变量副本的值写回主内存
但是由于CPU的随机性,可能一个线程没有完成这个三个步骤,执行权被其他线程抢走了,就破坏了原子性。

<3>AtomicInteger[原子类] 方法

//AtomicInteger[原子类] 方法
public class Demo2 {public static void main(String[] args) {//构造方法1  public AtomicInteger() 空参构造,初始值默认为0//构造方法2  public AtomicInteger(int number) 初始值默认为int//int get():获取值AtomicInteger ac = new AtomicInteger(10);System.out.println(ac.get());//get返回的值可再进行其他操作//int getAndIncrement():以原子方式将当前值加1,注意,这里返回的是自增前的值。System.out.println(ac.getAndIncrement());System.out.println(ac);System.out.println("----------------------------------------");//int incrementAndGet():以原子方式将当前值加1,注意,这里返回的是自增后的值。AtomicInteger ac2 = new AtomicInteger(10);System.out.println(ac2.incrementAndGet());//int addAndGet(int data):以原子方式将参数与对象中的值相加,并返回结果。System.out.println(ac2.addAndGet(10));//int getAndSet(int value):以原子方式设置为newValue的值,并返回旧值。System.out.println(ac2.getAndSet(30));//查看新值System.out.println(ac2);}
}打印结果:
--------------------------------------------------------------------------------
10
10
11
----------------------------------------
11
21
21
30

<4>AtomicInteger保证线程安全【小男孩送冰淇淋案例】

public class Demo1 {public static void main(String[] args) {MyAtomThread myAtomThread = new MyAtomThread();for (int i = 0; i < 100; i++) {new Thread(myAtomThread).start();}}
}//具体实现类
public class MyAtomThread implements Runnable {private int count =0;//记录送冰淇淋的数量@Overridepublic void run() {for (int i = 0; i < 100; i++) {//1,从共享数据中读取数据到本线程栈中//2,修改本线程栈中变量副本的值//3,会把本线程栈中变量副本的值赋值给共享数据count++;System.out.println("已经送了"+count+"冰淇淋");}}
}打印结果:
--------------------------------------------------------------------------------
已经送了1冰淇淋
......
已经送了9999冰淇淋
已经送了10000冰淇淋

<5>AtomicInteger原子性原理 :CAS算法和自旋

先获取主内存变量值
// 在修改共享数据的时候,把原来的旧值记录下来了。
// 如果现在内存中的值跟原来的旧值一样[compareAndSet],证明没有其他线程操作过内存值,则修改成功。
compareAndSet【比较内存中的值,旧值是否相等,如果相等就把修改后的值写到内存中,返回true,表示修改成功】
// 如果现在内存中的值跟原来的旧值不一样了[compareAndSet],证明已经有其他线程操作过内存值了。
// 则修改失败,需要获取现在最新的值,再次进行操作,这个重新获取就是自旋。

3.悲观锁【synchronized】和乐观锁【CAS】

<1>相同点:在多线程情况下,都可以保证共亨数据的安全性。

<2>不同点:
synchronized总是从最坏的角度出发,认为每次获取数据的时候,别人都有可能修改。所以在每次操作共享数据之前,都会上锁。(悲观锁)
cas是从乐观的角度出发,假设每次获取数据别人都不会修改,所以不会上锁。只不过在修改共享数据的时候,会检查一下,别人有没有修改过这个数据。
如果别人修改过,那么我再次获取现在最新的值。
如果别人没有修改过,那么我现在直接修改共享数据的值。(乐观锁)

【注:synchronized和volatile都不具备原子性】

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

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

相关文章

Maven Optional Exclusions使用区别

转载自 Maven Optional & Exclusions使用区别 Optional和Exclusions都是用来排除jar包依赖使用的&#xff0c;两者在使用上却是相反。 Optional定义后&#xff0c;该依赖只能在本项目中传递&#xff0c;不会传递到引用该项目的父项目中&#xff0c;父项目需要主动引用该依赖…

为什么jdk的CLASSPATH环境变量需要设置rt.jar 和 tools.jar

How Classes are Found 中有说明&#xff1a;&#xff08;java启动类文件在 rt.jar中&#xff0c; 而 工具类文件在 tools.jar 中&#xff09; How the Java Launcher Finds Classes The Java launcher, java, initiates the Java virtual machine. The virtual machine searc…

线程池的实现

1.创建线程池 API提供了一个工具类叫Executors&#xff0c;可以用它的方法生成不同特点的线程池&#xff0c;返回一个ExecutorService对象。 <1>Executors.newCachedThreadPool() 【池子中默认是空的&#xff0c;最多可以容纳int类型的最大值】 <3>Executors.new…

JSON Web Token (JWT),服务端信息传输安全解决方案

转载自 JSON Web Token (JWT)&#xff0c;服务端信息传输安全解决方案JWT介绍 JSON Web Token(JWT)是一种开放标准(RFC 7519)&#xff0c;它定义了一种紧凑独立的基于JSON对象在各方之间安全地传输信息的方式。这些信息可以被验证和信任&#xff0c;因为它是数字签名的。JWTs可…

thinking-in-java(18) java io

【0】README&#xff1a;本篇文章是以 thinking in java 为基础梳理的&#xff1b; 【18.1.1 目录列表器】 // 传入正则表达式以过滤文件名如 (.*src)* public class DirList {public static void main(String[] args) {File path new File(".");String[] list; i…

并发工具类【线程安全相关的类】

1.Hashtable和ConcurrentHashMap Hashtable&#xff1a;哈希表结构&#xff08;数组链表&#xff09;&#xff0c;线程安全的(同步代码块&#xff0c;效率低) ConcurrentHashMap&#xff1a; jdk7:采用Segment数组[不会扩容] HashEntry[二次哈希计算存入的位置,可扩容]&#…

JSON Web Token (JWT)生成Token及解密实战

转载自 JSON Web Token (JWT)生成Token及解密实战昨天讲解了JWT的介绍、应用场景、优点及注意事项等&#xff0c;今天来个JWT具体的使用实践吧。从JWT官网支持的类库来看&#xff0c;jjwt是Java支持的算法中最全的&#xff0c;推荐使用&#xff0c;网址如下。https://github.co…

java中两个map的融合(两个map有相同字段)

试想这样一个场景&#xff1a; 数据库表中 有 城市信息表 city_tbl&#xff1b; 有院士信息表 ys_tbl &#xff0c;其中院士有城市id字段&#xff08;id&#xff09;&#xff1b; 但是不是所有城市都有院士&#xff1b; 我们想要得到 城市的详细信息&#xff0c;包括院士个数…

网络编程实现

1.网络编程三要素 1.IP地址&#xff1a;网络中设备的唯一标识IPv4: 由4个字节组成&#xff0c;点分十进制表示法IPv6: 由16个字节组成&#xff0c;冒分十六进制表示法"127.0.0.1"本地主机网络地址【用于测试】相关命令&#xff1a;ipconfig: 查看本机在当前网络环境…

通用唯一标识码UUID的介绍及使用

转载自 通用唯一标识码UUID的介绍及使用。什么是UUID&#xff1f; UUID全称&#xff1a;Universally Unique Identifier&#xff0c;即通用唯一识别码。 UUID是由一组32位数的16进制数字所构成&#xff0c;是故UUID理论上的总数为16^32 2^128&#xff0c;约等于3.4 x 10^38。也…

IEEE论文检测的字体未嵌入问题Times New Roman,Bold, Times New Roman,Italic is not embedded解决方法

【1】README 毕业前写了一篇 英文paper&#xff0c; 接受后&#xff0c;需要提交到 IEEE PDF Express 做格式检测&#xff1b;&#xff1b;latex源码中引用了 Visio生成的算法流程图&#xff0c;PDF文件&#xff1b; 谁料&#xff0c;哥子提交上去后&#xff0c;报如下错误&…

类加载器的创建

1.什么是类加载器 <1>概念&#xff1a;类加载器是用来加载类的工具(从硬盘加载到JVM内存) <2>类加载器的加载时机【类在使用时才被加载&#xff0c;不使用不加载】 a.创建类的对象时 b.通过类名调用静态方法时 c.通过反射加载类 <3>3.类加载器的分类 a.启动…

Java 必看的 Spring 知识汇总

转载自 Java 必看的 Spring 知识汇总Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而&#xff0c;Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性的角度而言&#xff0c;绝大部分Java应用…

Java 截取反斜杠--java使用split拆分特殊字符

orgn link : http://blog.csdn.net/scy411082514/article/details/7987852 Java 截取反斜杠 replaceAll和split &#xff08;“\”&#xff09; 问题解决办法 2009年07月15日 星期三 上午 11:26 xxx.split("\\") 显然得不到想要的结果 正确方法 xxx.split(&qu…

反射的实现

1.获取类的字节码对象 //获取类的字节码对象 public class Demo1 {public static void main(String[] args) throws ClassNotFoundException {//方式1&#xff1a;类名.ClassClass<?> clazz1 Student.class;//方式2&#xff1a;对象名.getClass()Student student new…

thinking-in-java(11) 持有对象

【11.1】泛型和类型安全的容器 &#xff08;1&#xff09;ArrayList<Apple> 中尖括号括起来的是&#xff1a; 类型参数&#xff0c;它指定了这个容器实例可以保存的类型&#xff1b; 【荔枝&#xff1a;有泛型和没有泛型的区别】 class Apple {private static long coun…

JDK9新特性实战:简化流关闭新姿势

转载自 JDK9新特性实战&#xff1a;简化流关闭新姿势。做Java开发的都知道&#xff0c;每个资源的打开都需要对应的关闭操作&#xff0c;不然就会使资源一直占用而造成资源浪费&#xff0c;从而降低系统性能。 关于资源的关闭操作&#xff0c;从JDK7-JDK9有了不少的提升及简化。…

XML配置文件

XML的语法 1.xml是由自定义的标签组成 <开始标签>标签体</结束标签> <自闭合标签/> 2.xml文件的语法 1)必须要有一个文档声明 <?xml version"1.0" encoding"UTF-8" ?>2)只有一个根标签3)特殊字符 如< > & 必须使用…

DevExperience(1710)

【1】Date 和 String 互转 // Date 和 String 互转。public static void main(String[] args) {SimpleDateFormat formatter new SimpleDateFormat("yyyyMMdd");// Date 转 StringString curDateStr formatter.format(new Date());System.out.println("curDat…

Java Jar包的压缩、解压使用指南

转载自 Java Jar包的压缩、解压使用指南什么是jar包 JAR&#xff08;Java Archive&#xff09;是Java的归档文件&#xff0c;它是一种与平台无关的文件格式&#xff0c;它允许将许多文件组合成一个压缩文件。 如何打/解包 使用jdk/bin/jar.exe工具&#xff0c;配置完环境变量后…