Java并发编程的艺术 记录(二)
volatile的应用
volatile的定义如下:Java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。Java语言提供了volatile,在某些情况下比锁要更加方便。如果一个字段被声明成volatile,Java线程内存模型确保所有线程看到这个变量的值是一致的。
缓存一致性协议(处理器):每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期了,当处理器发现自己缓存行对应的内存地址被修改,就会将当前处理器的缓存行设置成无效状态,当处理器对这个数据进行修改操作的时候,会重新从系统内存中把数据读到处理器缓存里。
volatile的两条实现原则 :
1)Lock前缀指令会引起处理器缓存回写到内存 。
2)一个处理器的缓存回写到内存会导致其他处理器的缓存无效 。
LinkedTransferQueue 待看。
synchronized的实现原理与应用
1.6及之后对synchronized做过优化。synchronized用的锁是存在Java对象头里的。
synchronized实现同步的基础:Java中的每一个对象都可以作为锁 。
synchronized锁的4种状态:级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态,这几个状态会随着竞争情况逐渐升级。锁可以升级但不能降级,意味着偏向锁升级成轻量级锁后不能降级成偏向锁。这种锁升级却不能降级的策略,目的是为了提高获得锁和释放锁的效率 。
偏向锁引入的目的:为了让线程获得锁的代价更低而引入了偏向锁 。
偏向锁的获得和撤销流程:偏向锁使用了一种等到竞争出现才释放锁的机制,所以当其他线程尝试竞争偏向锁时,持有偏向锁的线程才会释放锁。
轻量级锁及膨胀流程图
锁的优缺点
处理器实现原子操作的两种方式:
1.总线锁
2.缓存锁
在Java中可以通过锁和循环CAS的方式来实现原子操作 。CAS(Compare and swap):CAS操作需要输入两个值,一个新值,一个旧值,在操作期间先比较旧值有没有发生变化,若无发生变化,则交换新值。
自旋CAS:循环进行CAS操作直到成功为止 。
示例:
package com.gjjun.concurrent; import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; /**
* 线程安全的自增和线程不安全的自增
* @author gjjun
* @create 2018/8/12
**/
public class CounterDemo {
private AtomicInteger ai = new AtomicInteger(0);
private int i = 0;
public static void main(String[] args) {
final CounterDemo cas = new CounterDemo();
List<Thread> threads = new ArrayList<>(16);
long start = System.currentTimeMillis();
for (int i = 0; i < 10; i++) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 10000; j++) {
cas.count();
cas.safeCount();
}
}
});
threads.add(t);
}
for (Thread thread : threads) {
thread.start();
}
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(cas.i);
System.out.println(cas.ai.get());
System.out.println(System.currentTimeMillis() - start);
} /**
* 不安全的计数
*/
private void count() {
i++;
} /**
* 使用cas实现线程安全计数器
*/
private void safeCount() {
for(;;) {
int i = ai.get(); boolean suc = ai.compareAndSet(i, ++i); if (suc) { break;
}
}
}
}
CAS的三个问题:
1.ABA问题。一个值由A到B再到A,CAS则认为是无变化的,但实际上是变化的。使用版本号解决:1A-2B-3A,类为AtomicStampedReference。
2.循环时间长开销大。可以使用处理器的pause指令,来略微提升效率。
3.只能保证一个共享变量的原子操作。可以使用锁,或者使用AtomicReference类保证引用对象之间的原子性。
Java并发编程的艺术 记录(二)的更多相关文章
- Java并发编程的艺术 记录(一)
模拟死锁 package com.gjjun.concurrent; /** * 模拟死锁,来源于<Java并发编程的艺术> * @Author gjjun * @Create 2018/ ...
- Java并发编程的艺术 记录(三)
Java内存模型 并发编程的两个关键问题: 1.线程之间如何通讯. 2.线程间如何同步. 两种方式:共享内存和消息传递. Java的并发采用的是共享内存模型,Java线程之间的通信总是隐式进行,整个通 ...
- Java并发编程的艺术(十二)——并发容器和框架
ConcurrentHashMap 为什么需要ConcurrentHashMap HashMap线程不安全,因为HashMap的Entry是以链表的形式存储的,如果多线程操作可能会形成环,那样就会死循 ...
- Java并发编程的艺术(十二)——线程安全
1. 什么是『线程安全』? 如果一个对象构造完成后,调用者无需额外的操作,就可以在多线程环境下随意地使用,并且不发生错误,那么这个对象就是线程安全的. 2. 线程安全的几种程度 线程安全性的前提:对『 ...
- Java并发编程的艺术 记录(四)
Java线程的状态: new :初始状态,但是还没调用start方法. runnable:运行状态. blocked:阻塞状态. waiting:等待状态,表示当前线程需要等待其他线程作出一些特定动作 ...
- Java并发编程的艺术(二)——volatile、原子性
什么是volatile Java语言允许线程访问共享变量,为了确保共享变量能够被准确一致地更新,如果一个字段被声明为volatile,那么Java内存模型将会确保所有线程看到这个变量时值是一致的.保证 ...
- java并发编程的艺术(二)---重排序与volatile、final关键字
本文来源于翁舒航的博客,点击即可跳转原文观看!!!(被转载或者拷贝走的内容可能缺失图片.视频等原文的内容) 若网站将链接屏蔽,可直接拷贝原文链接到地址栏跳转观看,原文链接:https://www.cn ...
- 《Java并发编程的艺术》读书笔记:二、Java并发机制的底层实现原理
二.Java并发机制底层实现原理 这里是我的<Java并发编程的艺术>读书笔记的第二篇,对前文有兴趣的朋友可以去这里看第一篇:一.并发编程的目的与挑战 有兴趣讨论的朋友可以给我留言! 1. ...
- Java并发编程的艺术(三)——volatile
1. 并发编程的两个关键问题 并发是让多个线程同时执行,若线程之间是独立的,那并发实现起来很简单,各自执行各自的就行:但往往多条线程之间需要共享数据,此时在并发编程过程中就不可避免要考虑两个问题:通信 ...
随机推荐
- NET Core 2.0使用Cookie认证实现SSO单点登录
NET Core 2.0使用Cookie认证实现SSO单点登录 之前写了一个使用ASP.NET MVC实现SSO登录的Demo,https://github.com/bidianqing/SSO.Sa ...
- 066 Plus One
给定一个非负整数组成的非空数组,给整数加一.可以假设整数不包含任何前导零,除了数字0本身.最高位数字存放在列表的首位.详见:https://leetcode.com/problems/plus-one ...
- C#远程连接sqlserver时,尝试读取或写入受保护的内存
管理员身份运行 cmd -> 输入 netsh winsock reset
- 关于一次性的数据输入,excel字符串连接保存到服务器还是CRUD?
一 开发中遇到个问题,线下一个紧急的活动,给一个excel的文件,要把里面的一次性的数据放进活动里面,说真的几百几千个数据啊,手写进数据库不是更麻烦了吗? 于是,备份方法就是写一个crud,让线下的人 ...
- springMVC数据校验与单文件上传
spring表单标签: <fr:from/> 渲染表单元素 <fr:input/>输入框组件 <fr:password/>密码框组件标签 & ...
- Java中的Serializable接口和transient关键字
Java中的Serializable接口和transient关键字 Table of Contents 1. 向memcached中放数据时遇到NotSerializableException异常 2 ...
- web端 repeat和简单控件
<%@ %> - 这里面写一些声明和引用的<% %> - 编写C#代码的<%= %><%# %> Repeater - 重复器 相当于winfo ...
- [VC]listctrl的基本用法
1 添加listctrl的头 m_list.setextendedstyle(LVS_EX_FULLROWSELECT||LVS_EX_GRIdLINES); m_list.insertcolum ...
- HDU - 5493 Queue 2015 ACM/ICPC Asia Regional Hefei Online(线段树)
按身高排序,每个人前面最高的人数有上限,如果超出上限说明impossible, 每次考虑最小的人,把他放在在当前的从左往右第k+1个空位 因为要求字典序最小,所以每次k和(上限-k)取min值. 没有 ...
- cv2.Canny 边缘检测
Canny边缘检测 Canny 的目标是找到一个最优的边缘检测算法,最优边缘检测的含义是: 好的检测 - 算法能够尽可能多地标识出图像中的实际边缘. 好的定位 - 标识出的边缘要尽可能与实际图像中 ...