用代码描述这么一个场景,在main方法中开启两个线程,其中一个线程t1往list里循环添加元素,另一个线程t2监听list中的size,当size等于5时,t2线程结束,t1线程继续执行,直到循环结束,试着想一想,以下代码能不能实现:

 package com.fanjf.thread;

 import java.util.ArrayList;
import java.util.List; public class Mycontainer {
static List<Integer> integers = new ArrayList<>(); public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
System.out.println("t1启动");
for(int i=0;i<10;i++){
integers.add(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("add:"+i);
}
System.out.println("t1结束");
}
}).start(); new Thread(new Runnable() {
public void run() {
System.out.println("t2启动");
while(true){
if(integers.size()==5){
break;
}
} System.out.println("t2结束");
} }).start();
} }

答案是不行,输出结果如下,且程序并没有结束,一直处于运行状态

t1启动
t2启动
add:0
add:1
add:2
add:3
add:4
add:5
add:6
add:7
add:8
add:9
t1结束

有并发编程经验的人应该很容易就能看出问题所在,这里涉及到了线程之间的可见性问题,只需要在上面第7行的integers变量前加上volatile便可以得到想要的结果,如下红色部分:

volatile static List<Integer> integers = new ArrayList<>();

输出结果如下:

t1启动
t2启动
add:0
add:1
add:2
add:3
t2结束
add:4
add:5
add:6
add:7
add:8
add:9
t1结束

这里的volatile作用是为了保证线程之间的可见性,java之间线程之间通信是通过共享内存来实现的,当t1线程向integers中add元素时,如果不加volatile,这个size的变化t2线程是无法感知的,因为当线程执行时,t2会在执行当前线程的cpu中缓存一份integers,t2会优先读取自己线程本地变量的integers,而不从主内存中读取,也就是两个线程之间是不可见的,当在这个共享变量加上volatile时,t1向integers中add元素,即修改了共享变量integers的值,程序会通知t2重新从主内存中读取共享变量的值,这时候t1和t2之间就是可见的,这其实是happens before规则中其中重要的一条:volatile的写happens before volatile的读,意思就是说一个线程对volatile修饰的变量的写操作对于其他线程来说一定是可见的,感兴趣的可以自己了解一下happens before规则。

并发编程之volatile的更多相关文章

  1. Java 并发编程之volatile关键字解析

    摘录 1. 计算机在执行程序时,每条指令都是在CPU中执行的,而执行指令过程中,势必涉及到数据的读取和写入.由于程序运行过程中的临时数据是存放在主存(物理内存)当中的,这时就存在一个问题,由于CPU执 ...

  2. Java并发编程之volatile的应用

    在多线程的并发编程中synchronized和volatile都扮演着重要的角色.volatile是轻量级的synchronized,它在多处理器的开发中保证了共享变量的可见性,可见性的意思是当一个线 ...

  3. java并发编程之volatile

    Java语言规范第三版中对volatile的定义如下:Java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量. 了解volatile关键字之 ...

  4. Java并发编程之volatile关键字解析

    一内存模型的相关概念 二并发编程中的三个概念 三Java内存模型 四深入剖析volatile关键字 五使用volatile关键字的场景 volatile这个关键字可能很多朋友都听说过,或许也都用过.在 ...

  5. 并发编程之volatile与JMM多线程内存模型

    一.通过程序看现象 在开始为大家讲解Java 多线程缓存模型之前,我们先看下面的这一段代码.这段代码的逻辑很简单:主线程启动了两个子线程,一个线程1.一个线程2.线程1先执行,sleep睡眠2秒钟之后 ...

  6. Java并发编程之volatile变量

    volatile提供了弱同步机制,用来确保将变量更新通知到其它线程.volatile变量不会被缓存在寄存器中或者对其它处理器不可见的地方,因此在读取volatile变量时总会返回最新写入的值.可以想象 ...

  7. Java并发编程之volatile关键字

    大概是因为项目.业务的原因,工作上几乎还没有使用过多线程相关的功能,相关知识差不多都忘了,所以最近补一下基础. volatile用来修饰共享变量,volatile变量具有 synchronized 的 ...

  8. 并发编程之wait()、notify()

    前面的并发编程之volatile中我们用程序模拟了一个场景:在main方法中开启两个线程,其中一个线程t1往list里循环添加元素,另一个线程t2监听list中的size,当size等于5时,t2线程 ...

  9. 并发编程之 Exchanger 源码分析

    前言 JUC 包中除了 CountDownLatch, CyclicBarrier, Semaphore, 还有一个重要的工具,只不过相对而言使用的不多,什么呢? Exchange -- 交换器.用于 ...

随机推荐

  1. 用存储过程向数据库添加大量数据【mysql】

    预分配ID的设计,需要先为数据库生成大量的数据.比如对用户ID有要求的系统,那么用户ID就要预先生成. 通过python,php,c/c++/c#,js等程序生成也是可以,但需要这些程序环境,而且单条 ...

  2. java class反编译工具----JD-GUI

    下载地址   http://jd.benow.ca/

  3. Go 反射

    基本了解 在Go语言中,大多数时候值/类型/函数非常直接,要的话,定义一个.你想要个Struct type Foo struct { A int B string } 你想要一个值,你定义出来 var ...

  4. 在centos中搭建基于nginx的apt源服务器,整合yum源和apt源在一台服务器

    1.首先关闭防护墙或者设置规则通过且关闭selinux 2.nginx-1.14.2版本(编译安装)-自定义安装路径 3.开启nginx目录浏览 以上步骤请参考前文:https://www.cnblo ...

  5. Zabbix3.4-RHEL 7.4 X64 YUM联网安装

    OS准备 关闭selinux vi /etc/selinux/config setenforce 0 开启防火墙80端口访问 firewall-cmd --permanent --add-rich-r ...

  6. 周一02.4变量&垃圾回收机制

    一.变量 1. 什么是变量 量:记录事物的某种状态,即事物典型的特征 变:事物的状态是可以发生变化的 2. 为何要用变量 是为了让计算机能够像人一样记录事物的状态 3. 如何用变量 (先定义后引用) ...

  7. 移动端左右滑动问题-html与css解决

    <!DOCTYPE html> <html> <head> <title>纯css实现左右滑动</title> <style type ...

  8. openstack 2019/4/28

    官网参考地址:https://docs.openstack.org/keystone/queens/install/index-rdo.html (但愿能看懂) 环境:这个部分解释如何按示例架构配置控 ...

  9. Scala--控制结构和函数

    一.条件表达式 val s = if(x > 1) 1 else -1 s 可以是 val var s = 0 if(x > 1) s = 1 else s = -1 s 必须是 var ...

  10. Django后端向前端直接传html语言防止转义的方法(2种)

    Django后端向前端直接传html语言防止转义的方法(2种) 目的,为了让前端对后端传输的这种方式不转义 1.使用mark_safe() from django.utils.safestring i ...