Java多线程-线程关键字(二)
Java中和线程相关的关键字就两:volatile和synchronized。
volatile以前用得较少,以后会用得更少(后面解释)。它是一种非常轻量级的同步机制,它的三大特性是:
1、保证可见性,即强制将CPU高速缓存的数据立即写入主存,会导致其他CPU核中对应的高速缓存内容无效,就像这样:

如果由于同步需要,某行代码使用了volatile关键字,那么当CPU内核1收到指令时,会立即将它位于高速缓存中的数据(这里是字符串“1”)写到主存中去,那么其余的数据(“哈哈”、“test”、9.9)会全部失效。
2、有序性(禁止指令重排)
所谓指令重排,就是对于int a = 0、 int b = 1这类赋值语句,编译成class字节码时,a = 0,b = 1的顺序可能会因为编译器的优化而导致和书写时的顺序不一致。但如果有c = a + b,那么这行代码必须在前两句的后面执行。这个不用深究,知道就好了。
3、不保证原子性
所谓不保证原子性,就是如果遇到多个线程同时执行i = i + 1,那么i可能就不能保证仅仅被加1了。
根据Java的内存模型整理出如下这些规则,看看就好,能理解就记住,理解不了也没关系,不用记:

下面还是以代码来说明:
public class VolatileTest extends Thread {
static boolean flag = true;
@Override
public void run() {
while (flag) {
}
System.out.println("子线程结束");
}
public static void main(String[] args) throws InterruptedException {
new Thread(new VolatileTest()).start();
TimeUnit.SECONDS.sleep(1);
flag = false;
System.out.println("主线程结束");
}
}
加上volatile之后,子线程就不会一直卡住了:
public class VolatileTest2 extends Thread {
volatile static boolean flag = true;
@Override
public void run() {
while (flag) {
}
System.out.println("子线程结束");
}
public static void main(String[] args) throws InterruptedException {
new Thread(new VolatileTest2()).start();
TimeUnit.SECONDS.sleep(1);
flag = false;
System.out.println("主线程结束");
}
}
其实在第一个类VolatileTest中,即使不用volatile关键字,也能让程序正常结束,只需要添加一行代码就行了:
public class VolatileTest3 extends Thread {
static boolean flag = true;
@Override
public void run() {
while (flag) {
// 只要在这里随便加一行代码,虽然原理不同,但效果和加了volatile一样
System.out.println(" ");
}
System.out.println("子线程结束");
}
public static void main(String[] args) throws InterruptedException {
new Thread(new VolatileTest3()).start();
TimeUnit.SECONDS.sleep(1);
flag = false;
System.out.println("主线程结束");
}
}
总结一下,适应volatile的条件:
1、对变量的写操作不依赖于当前值,就是不会出现 x++ 或 x = x + y 这样的自增性质的语句;
2、变量没有包含在具有其他变量的代码中,就是不会出现 if(x > y) { // dosomething; } 这样的语句,因为这样的话,dosomething就不是线程安全的。
所以适合使用volatile的场景是:
1、状态标记量
2、双重检查
状态标记量:只设置简单的状态值,希望立即看到,且无其他变量参与。之前Volatile2中的flag就是这样的状态标记量。
双重检查(这个有点生僻冷门,不深究)。
因为目前synchronized的性能已经有了大幅提升,而且机器硬件的性能也较之前翻了几十倍,volatile存在的意义已经不大了。所以如果对volatile的理解不够深入,就干脆不用理解了。
再来看另一个重量级选手:synchronized
synchronized关键字用于解决多个线程之间的资源共享问题,通常有三大作用域:
1、静态方法:public synchronized static void methodName(),进入方法前要获得当前类对象的锁;
2、实例方法:public synchronized void methodName(),进入方法前要获得当前对象实例的锁;
3、代码块:最常用,指定一个特别的加锁对象,进入同步代码块前要获得这个对象锁。
这几个就不一个个地说了,因为网上这类例子太多了。
就简单说一下volatile和synchronized的比较:
1、volatile是synchronized的轻量级实现,性能要比synchronized要好;
2、volatile只能修饰变量,synchronized只能修饰方法和代码块;
3、volatile不会造成阻塞,synchronized会。
最后再说一个我之前遇到的小问题:
如果使用的IDE是Eclipse,那么当前活动的线程数量可能是1;
但如果使用的IDE是IDEA,那么当前活动的线程数量可能是2;
有图为证:

这是因为在IDEA中多了一个Monitor Ctrl-Break。

Java多线程-线程关键字(二)的更多相关文章
- Java多线程学习(二)synchronized关键字(2)
转载请备注地址:https://blog.csdn.net/qq_34337272/article/details/79670775 系列文章传送门: Java多线程学习(一)Java多线程入门 Ja ...
- Java多线程学习(二)synchronized关键字(1)
转载请备注地址: https://blog.csdn.net/qq_34337272/article/details/79655194 Java多线程学习(二)将分为两篇文章介绍synchronize ...
- “全栈2019”Java多线程第二十二章:饥饿线程(Starvation)详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- “全栈2019”Java多线程第十二章:后台线程setDaemon()方法详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- java 多线程—— 线程让步
java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...
- java 多线程—— 线程等待与唤醒
java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...
- Java 多线程 —— synchronized关键字
java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...
- Java多线程--线程及相关的Java API
Java多线程--线程及相关的Java API 线程与进程 进程是线程的容器,程序是指令.数据的组织形式,进程是程序的实体. 一个进程中可以容纳若干个线程,线程是轻量级的进程,是程序执行的最小单位.我 ...
- Java 多线程 - synchronize 关键字
目录 Java 多线程 - synchronize 关键字 Java 多线程 - synchronize 关键字 学习自 http://cmsblogs.com/?p=2071 https://www ...
随机推荐
- CAD二次开发---关于JoinEntity出现eNotApplicable的问题
作者在使用JoinEntity时出现eNotApplicable的问题,查阅了Autodesk论坛的相关帖子,发现大多数人都有遇到这个问题,但没有找到合适的解决方法,可能原因是进行Join时两Curv ...
- [NOIP2018提高组] 保卫王国 (树链剖分+动态DP)
题面 题目链接-Luogu 题目链接-Loj(要加Freopen) 题解 什么是动态DP? OneInDark:你不需要知道这么多,你只需要知道是利用了广义矩阵乘法就够了! 广义矩乘 广义矩阵乘法,简 ...
- 【mido】python的midi处理库
安装mido库:pip install mido pipy地址:https://pypi.org/project/mido/ mido官方文档:https://mido.readthedocs.io/ ...
- Mybatis中多对一与一对多
多对一的处理 在pojo中就有 Student private String name; private String id; private Teacher teacher; 比如说多个学生对应着一 ...
- 第七十三篇:解决Vue组件中的样式冲突
好家伙, 1.组件之间的样式冲突 默认情况下,写在.vue组件中的样式会全局生效,因此很容易造成多个组件之间的样式冲突问题. 举个例子: 我们在Left.vue的组件中添加样式 <templat ...
- C++ 初识函数模板
1. 前言 什么是函数模板? 理解什么是函数模板,须先搞清楚为什么需要函数模板. 如果现在有一个需求,要求编写一个求 2 个数字中最小数字的函数,这 2 个数字可以是 int类型,可以是 float ...
- KingbaseES V8R6 锁等待检测
背景 对于多数数据库,dba技能之一就是查找锁.锁的存在有效合理的在多并发场景下保证业务有序进行.下面我们看一下KingbaseESV8R6中查找阻塞的方法. 1.找到"被阻塞者" ...
- 创建x11vnc系统进程
〇.前言 为方便使用vnc,所以寻找到一个比较好用的vnc服务端那就是x11vnc,索性就创建了一个系统进程 一.环境 系统:银河麒麟v4-sp2-server 软件:x11vnc[linux下].V ...
- JavaWeb核心篇(2)——Request和Response
JavaWeb核心篇(2)--Request和Response 上篇文章中提及到了Servlet,在Servlet中我们主要继承了HTTPServlet类,在HTTPServlet类中我们会接触到两个 ...
- Linux宝塔后台管理地址使用SSL,并部署非443端口的https
上传你的key和pem,然后点设置 点击配置文件 插入代码 1 ssl on; 2 ssl_certificate /xxx/yyy/zzz.pem; 3 ssl_certificate_key /x ...