一个关于Java 多线程问题的知识点
这个程序运行结果会是什么?
public class Main {static class ListAdd {
private static List list = new ArrayList(); public void add() {
list.add("baoer");
} public int size() {
return list.size();
} } public static void main(String[] args) throws IOException { final ListAdd list = new ListAdd(); new Thread(new Runnable() {
@Override
public void run() {
try {
for (int i= ; i < ; i++) {
Thread.sleep(500);
list.add();
System.out.println("线程:" + Thread.currentThread().getName() + " 添加了一个元素" );
} } catch (InterruptedException e) {
e.printStackTrace();
}
}
},"T1").start(); new Thread(new Runnable() {
@Override
public void run() {
while (true) { if (list.size()== ) {
System.out.println("当前线程收到通知 " + Thread.currentThread().getName() + " list.size=5线程停止");
throw new RuntimeException();
} }
}
}, "T2").start(); // fun(); }
如果知道ArrayList不是线程安全的也许答案就是线程T1运行结束,T2一直执行下去不会抛出异常而结束。事实结果也确是这样。但这样的执行结果背后却值得深思。
问题1:这是因为有可能T2线程某次读入缓存的size为4,但下一次读入缓存的数字是6,所以永远进入不了if.
但由于线程T1每次add之后都sleep 500 毫秒所以这种可能不存在。
问题2:在T2 if(list.size() == 5) 之前将size放入一个Hashset发现Hashset中只有一个值 0 。这说明size根本没有从主内存中刷新到T2工作内存中,为什么主存中size值都更新了还不刷新到工作内存中呢?不是有缓存一致性吗?
原因就是 T2中的size根本没有在T2的缓存中!这是编译器干的事! 编译器发现是一个while(true),并且要频繁使用size,就会把size放在寄存器中提高访问速度,缓存不保存size。所以即使有缓存一致性size永远无法更新。
问题3: 为什么list是volatile 就会得到正确结果?
对于volatile变量 编译器不会把它放入寄存器中,在缓存中volatile 可以保证可见性,并且根据happens-before规则 volatile 的读取一定在写入之后。
问题4: 为什么在if判断前加 System.out.println(list.size()); 也会的到正确结果?
通过查看System.out.println 源码发现执行输出语句时要加同步锁,
JMM关于synchronized的两条规定:
1. 线程解锁前,必须把共享变量的最新值刷新到主内存中
2. 线程加锁时,先清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新读取最新的值。
由于清空工作内存中的值所以寄存器中的值也失效了,虽然此时值没在工作内存中,但也寄存器也会刷新再从工作内存中读取。
问题5: 为什么在if判断前加Thread.sleep(0)或者Thread.yield();也会的到正确结果?
这涉及到了线程的上下文切换,一但切换上下文工作内存中的就值就会失效,系统保存了线程的状态,下次切换回来时重新从内存中读值。
一个关于Java 多线程问题的知识点的更多相关文章
- java多线程-概念&创建启动&中断&守护线程&优先级&线程状态(多线程编程之一)
今天开始就来总结一下Java多线程的基础知识点,下面是本篇的主要内容(大部分知识点参考java核心技术卷1): 1.什么是线程以及多线程与进程的区别 2.多线程的创建与启动 3.中断线程和守护线程以及 ...
- Java多线程的下载器(1)
实现了一个基于Java多线程的下载器,可提供的功能有: 1. 对文件使用多线程下载,并显示每时刻的下载速度. 2. 对多个下载进行管理,包括线程调度,内存管理等. 一:单个文件下载的管理 1. 单文件 ...
- Java多线程编程实战指南(核心篇)读书笔记(五)
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76730459冷血之心的博客) 博主准备恶补一番Java高并发编程相 ...
- Java最重要的21个技术点和知识点之JAVA多线程、时间处理、数据格式
(四)Java最重要的21个技术点和知识点之JAVA多线程.时间处理.数据格式 写这篇文章的目的是想总结一下自己这么多年JAVA培训的一些心得体会,主要是和一些java基础知识点相关的,所以也希望能 ...
- java多线程知识点
下面是我学习多线程记录的知识点,并没详细讲解每个知识点,只是将重要的知识点记录下来,有时间可以看看,如果有不对的地方,欢迎大家指出,谢谢! 1.多线程的状态和创建方式: 线程的状态: ...
- Java多线程学习(五)线程间通信知识点补充
系列文章传送门: Java多线程学习(二)synchronized关键字(1) Java多线程学习(二)synchronized关键字(2) Java多线程学习(三)volatile关键字 Java多 ...
- Java 多线程与并发【知识点笔记】
Java 多线程与并发[知识点笔记] Java多线程与并发 先说一下线程与进程的由来: 在初期的计算机,计算机只能串行执行任务,并且需要长时间的等待用户的输入才行 到了后来,出现了批处理,可以预先将用 ...
- java 多线程——一个定时调度的例子
java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...
- Java Tread多线程(0)一个简单的多线程实例
作者 : 卿笃军 原文地址:http://blog.csdn.net/qingdujun/article/details/39341887 本文演示,一个简单的多线程实例,并简单分析一下线程. 编程多 ...
随机推荐
- HDU 4582 DFS spanning tree(DFS+贪心)(2013ACM-ICPC杭州赛区全国邀请赛)
Problem Description Consider a Depth-First-Search(DFS) spanning tree T of a undirected connected gra ...
- 学习bash——管道命令
摘要:管道命令概述.常见管道命令的使用(cut/grep.sort/wc/uniq.tee.tr/col/join/paste/expand.xargs.减号-) 一.概述 命令执行完会在屏幕上打印相 ...
- Caused by: redis.clients.jedis.exceptions.JedisDataException: WRONGTYPE Operation against a key holding the wrong kind of value
对错误类型key的操作,也就是说redis中没有你当前操作的这个key,而你用这个key去执行某些操作!检查key是否正确
- http长连接和短连接以及连接的本职
HTTP长连接和短连接原理浅析 本文主要讲了,http长连接本质是tcp的长连接. 网络通信过程中,建立连接的本质是什么? 连接的本质 建立连接这个词,是从早期的电话系统中来的,那个时候,“建立连接” ...
- Leader Election
Leader Election Zookeeper的基本操作 Zookeeper虽然是分布式系统,但它并不是为文件存储而设计的,Zookeeper里存储的一般是配置信息和源信息.实际上,Zookeep ...
- js & disabled mouse right button menus
js & disabled mouse right button menus 网页可以屏蔽 F12 https://www.cnblogs.com/Marydon20170307/p/9122 ...
- 正确答案 [Hash/枚举]
正确答案 题目描述 小H与小Y刚刚参加完UOIP外卡组的初赛,就迫不及待的跑出考场对答案. "吔,我的答案和你都不一样!",小Y说道,"我们去找神犇们问答案吧" ...
- Leetcode 45. Jump Game II(贪心)
45. Jump Game II 题目链接:https://leetcode.com/problems/jump-game-ii/ Description: Given an array of non ...
- rsync安装使用详解
rsync是类unix系统下的数据镜像备份工具,从软件的命名上就可以看出来了——remote sync.它的特性如下: 可以镜像保存整个目录树和文件系统. 可以很容易做到保持原来文件的权限.时间.软硬 ...
- 封装getByClass(JS获取class的方法封装为一个函数)
获取方法一(普通版) 获取单一的class: function getByClass(oParent, sClass) {//两个形参,第一个对象oParent 第二个样式名class var aEl ...