1.引子
在java多线程并发编程中,有八大基础核心。 看看都有哪八大基础核心呢?它们分别是: 1.建立线程的方式 2.线程启动 3.线程中止 4.线程生命周期 5.线程相关的方法 6.线程相关的属性 7.线程异常处理 8.线程安全 今天咱们从第八个基础核心开始:线程安全
2.考考你
#前情回顾 1.多线程编程中,比较为难,又须要重点关注的一个话题,就是线程安全 2.须要从理论、和实战多个角度去看 3.本着一篇文章,信息量不要太多的原则 4.本篇文章仅相对全面的梳理线程安全的基础 5.更多内容,结合JUC的内容,推荐了解的内容有: 线程池、锁、CAS、ThreadLocal 并发集合、并发流程控制、AQS #考考你 1.你知道多线程的理论基础有哪些吗? 2.你知道线程的实现方式有哪些吗? 3.你知道多线程安全的三要素吗? 4.你知道java的内存模型JMM吗? 5.你知道让线程安全的常规手段吗? 6.你知道java中的volatile关键字吗?
3.案例
3.1.困惑的i++操做
简述:html
1.在咱们的平常开发中,常常会写:i++这样的操做java
2.问题:那么它究竟是不是线程安全的呢?编程
3.关键点:问题的关键在于i++是否是原子性操做。即i++对于操做系统,或者说对于jvm执行子系统,是一条指令,仍是多条指令?安全
3.1.1.案例代码
package com.anan.thread.threadsafe; /** * 让人困惑的i++操做 */ public class ThreadSafeIAddOper { // 定义自增操做变量:i public static int i_add = 0; // 在方法中,进行i_add的自增操做 public static void addI(){ i_add++; } public static void main(String[] args) { // 建立20个线程,并行执行i_add自增操做 Runnable r1 = new MyRunnable(); // for循环,建立20个线程 for (int i = 0; i < 20; i++) { new Thread(r1).start(); } // 等待20个子线程执行结束后,主线程main输出i_add的值 while(Thread.activeCount() > 2){ ; } System.out.println("i_add变量最终值:" +i_add); } /** * 实现Runnable接口,建立线程 */ static class MyRunnable implements Runnable{ public void run() { // for循环,执行i_add自增操做:10000次 for (int i = 0; i < 10000; i++) { addI(); } } } }
3.1.2.执行结果
3.1.3.ThreadSafeAddOper字节码文件内容
简述:bash
1.彩蛋:经过javap工具,查看字节码文件结构多线程
2.说明i++操做,对于jvm执行子系统,不是原子性(是由多条指令组成)并发
3.如下是类:ThreadSafeIAddOper,对应的class文件内容jvm
D:\03other\02study\coding\mypro\thread-pro\target\classes>javap -v com.anan.thread.threadsafe.ThreadSafeIAddOper Classfile /D:/03other/02study/coding/mypro/thread-pro/target/classes/com/anan/thread/threadsafe/ThreadSafeIAddOper.class Last modified 2020-2-15; size 1259 bytes MD5 checksum 6b289d7c5da1749f03e41da116a3b9a6 Compiled from "ThreadSafeIAddOper.java" public class com.anan.thread.threadsafe.ThreadSafeIAddOper minor version: 0 major version: 49 flags: ACC_PUBLIC, ACC_SUPER Constant pool: ......内容省略...... public static void addI(); descriptor: ()V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=0, args_size=0 0: getstatic #10 // Field i_add:I 3: iconst_1 4: iadd 5: putstatic #10 // Field i_add:I 8: return LineNumberTable: line 13: 0 line 14: 8 LocalVariableTable: Start Length Slot Name Signature public static void main(java.lang.String[]); .......内容省略...... D:\03other\02study\coding\mypro\thread-pro\target\classes>
3.1.4.i++对应的字节码指令说明
简述:工具
1.经过截图,能够看到一个i++操做,在字节码层面,对应了四条jvm字节码指令:学习
getstatic、iconst_一、iadd、putstatic
2.说明对于jvm来讲,i++不是原子性操做
3.2.线程安全基本手段:锁
简述:
1.改造3.1案例代码,经过加锁实现:多条指令操做的原子性。从而实现线程安全。
2.给addI方法,增长synchronized同步锁
执行结果:
3.3.关键字volatile错误使用案例
简述:
改造3.1.案例代码,经过volatile关键字修饰:
1.说明volatile关键字,只能保障线程的可见性(即一个线程修改了volatile关键字修改的变量后,会当即刷新到主内存,让其它线程可见)。
2.但volatile关键字,不能保障原子性,对于i++操做,它仍是不能保障线程安全
3.关于volatile关键字的正确使用方式,请看讨论分享中内容说明。
执行结果:
4.讨论分享
#考考你答案 1.你知道多线程的理论基础有哪些吗? 1.1.进程与线程的区别 1.2.线程实现方式 1.3.线程安全三要素 1.4.java内存模型JMM 1.5.锁 2.你知道进程与线程的区别吗? 2.1.进程是操做系统【分配资源】的最小单位 2.2.线程是操做系统【调度】的最小单位 3.你知道线程的实现方式有哪些吗? 3.1.基于操做系统内核实现方式(内核线程) 3.2.基于用户进程实现方式(用户态线程,即协程) 3.3.java的线程实现方式是:内核线程实现方式 4.你知道多线程安全的三要素吗? 4.1.线程安全要素一:原子性 4.2.线程安全要素二:可见性 4.3.线程安全要素三:有序性 5.你知道java的内存模型JMM吗? 5.1.参见附图 6.你知道java编程中,线程安全的常规手段吗? 6.1.线程安全常规手段一:加锁 6.2.线程安全常规手段二:消除共享资源 7.你知道java中的volatile关键字吗? 7.1.volatile关键字是一种轻量级线程安全实现方式 7.2.volatile关键字的底层原理:保证可见性,禁止重排序 7.3.使用volatile关键字注意事项: a.volatile关键字修饰变量值修改,不依赖原来的值;或者只有单一线程进行修改 b.volatile关键字修饰的变量,不与其它变量一块儿参与原子性约束 c.知足a、b两条,那么volatile关键字修饰的变量,在多线程下是线程安全的
java内存模型JMM:
(到这里,多线程基础编程暂时告一段落,本系列是学习笔记,参考了悟空老师的课程:《Java并发核心知识体系精讲》。欢迎你们去学习悟空老师的课程,讲的很是好!同时向悟空老师问好!)