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 ...
随机推荐
- GitHub Pages 站点建设
1.简介 GitHub Pages 是通过 GitHub 托管和发布的公共网页,将纯文本转换为静态博客网站. 您可以使用 GitHub Pages 来展示一些开源项目.博客甚或分享您的简历,有内存限制 ...
- 原生应用、Web 应用和混合应用的概念,以及 Flutter 技术是什么
应用类型 原生应用 原生应用就是使用特定的语言开发的应用,例如 Android 原生应用.Windows 原生应用.iOS 原生应用等.开发 Android 原生应用时,其特定的编程语言为 Java ...
- 刷题记录:Codeforces Round #719 (Div. 3)
Codeforces Round #719 (Div. 3) 20210703.网址:https://codeforces.com/contest/1520. 没错,我是个做div3的蒟蒻-- A 大 ...
- React报错之Parameter 'event' implicitly has an 'any' type
正文从这开始~ 总览 当我们不在事件处理函数中为事件声明类型时,会产生"Parameter 'event' implicitly has an 'any' type"错误.为了解决 ...
- 部署k8s的heapster监控
Heapster是容器集群监控和性能分析工具,天然的支持Kubernetes和CoreOS heapster监控目前官网已经不更新,部署学习使用 heapster: 收集监控数据 influxdb:数 ...
- scp复制发送文件夹到其他服务器上
简述scp: scp是secure copy的简写,是linux系统下基于ssh登陆进行安全的远程文件拷贝命令. 写法: scp [可选参数] 登录名@地址:源路径 目标路径. 举例:scp -r ...
- EL&JSTL笔记------jsp
今日内容 1. JSP: 1. 指令 2. 注释 3. 内置对象 2. MVC开发模式 3. EL表达式 4. JSTL标签 5. 三层架构 JSP: 1. 指令 * 作用:用于配置JSP页面,导入资 ...
- 第四章 部署K8s前准备工作
一.主机准备 1.硬件 准备5台2C/2g/50g虚拟机: Centos7.6系统 2.集群规划 使用10.4.7.0/24网络 IP 主机名 10.4.7.11 hdss7-11.host.com ...
- KingbaseES R3集群备库执行sys_backup.sh物理备份案例
案例说明: KingbaseES R3的后期版本支持通过sys_backup.sh执行sys_rman的物理备份,实际上是调用了sys_rman_v6的工具做物理备份.本案例是在备库上执行集群的备份, ...
- ASP.NET MVC 对于视图引擎的优化
我经常使用asp.net MVC框架来做网站.总的来说,MVC框架是一个非常优秀的框架.相对于曾经的web form模式,我个人感觉分工更加合理思路也更加清晰,但是交给开发人员的工作也相对变多了. 当 ...