无锁

一、概述

无锁是处理并发的一种乐观策略,它会假设对资源的访问是没有冲突的。既然没有冲突自然不需要等待,所以所有的线程都可以在不停顿的状态下执行。那遇到冲突怎么办?接下来请看,无锁绝招“CAS”即比较交换术。

二、CAS原理

CAS即Compare and swap.其算法过程是这样的:它有三个参数:

1.V表示要更新的变量

2.E表示期望值

3.N表示新值

仅当V等于E时,才会将V设为N。如果V和N不同,则说明有其他线程做了更新,则该线程什么都不做。当多个线程同时使用CAS进行变量操作时,只有一个会更新成功,其余都会失败。失败的线程不会被挂起,而是进行重试。

三、无锁的线程安全整数:AtomicInteger

AtomicInteger主要方法如下(对于其他无锁线程安全类,其方法类似):

public final int get() //取得当前值
public final void set(int newValue) //设置当前值
public final int getAndset(int newValue) //设置新值返回旧值
public final boolean compareAndSet(int except,int u) //如果当前值为except则设为u
public final int getAndIncrement() //当前值加1返回旧值
public final int getAndDecrement()
public final int getAndAdd(int delta)
public final int incrementAndGet()
public final int decrementAndGet()
public final int addAndGet()

就AtomicInteger核心字段:

private volatile int value; //代表AtomicInteger当前的值
private static final long valueOffset; //value字段的偏移量

AtomicInteger的使用示例:

public class AutomicIntegerDemo {

    static AtomicInteger i=new AtomicInteger();

    public static class addThread implements Runnable{

        @Override
public void run() {
for(int j=0;j<1000;j++){
i.incrementAndGet();
}
}
} public static void main(String[] args) throws InterruptedException {
Thread[] ts=new Thread[10];
for(int j=0;j<10;j++){
ts[j]=new Thread(new addThread());
} for(int j=0;j<10;j++) ts[j].start();
for (int j=0;j<10;j++) ts[j].join(); System.out.println(i);
}
}

相比使用锁,使用无锁会有更好的性能。

四、CAS算法逻辑上瑕疵及解决办法:AtomicStampedReference

CAS算法逻辑上的瑕疵:当你获得对象当前数据后,在准备修改为新值前,对象的值被其他对象连续修改了两次,而经过这两次修改后,对象的值又恢复到旧值。这样,当前线程就无法判断该值是否被修改过。也就是说你修改的对象数值没有过程状态信息。

AtomicStampedReference内部不仅维护了对象值还维护了一个状态值。

五、无锁数组

当前可用的原子数组有:AtomicIntegerArray,AtomicLongArray和AtomicReferenceArray

public class AtomicIntegerArrayDemo {

    static AtomicIntegerArray array=new AtomicIntegerArray(10);

    public static class addThread implements Runnable{

        @Override
public void run() {
for (int j=0;j<1000;j++){
array.getAndIncrement(j%array.length());
}
}
} public static void main(String[] args) throws InterruptedException {
Thread[] ts=new Thread[10];
for (int j=0;j<10;j++){
ts[j]=new Thread(new addThread());
} for (int j=0;j<10;j++) ts[j].start(); for (int j=0;j<10;j++) ts[j].join(); System.out.println(array);
}
}

六、让普通变量也享受原子操作:AtomicIntegerFieldUpdater

public class AtomicIntegerFieldUpdaterDemon {

    public static class Candidate{
int id;
volatile int score;
} public final static AtomicIntegerFieldUpdater<Candidate> scoreUpdater=
AtomicIntegerFieldUpdater.newUpdater(Candidate.class,"score"); public static AtomicInteger checkScore=new AtomicInteger(0); //用于检测 public static void main(String[] args) throws InterruptedException {
final Candidate candidate=new Candidate();
Thread[] threads=new Thread[1000];
for (int i=0;i<1000;i++){
threads[i]=new Thread(){
public void run(){
if (Math.random()>0.4){
scoreUpdater.incrementAndGet(candidate);
checkScore.incrementAndGet();
}
}
};
threads[i].start();
} for (int i=0;i<1000;i++) threads[i].join();
System.out.println("score="+candidate.score);
System.out.println("checkScore="+checkScore);
}
}

注意事项:

1.Updater只能修改可见范围内的变量。

2.变量必须是volatile

3.变量不能是static的

Java并发程序设计(七)乐天派:无锁的更多相关文章

  1. 【实战Java高并发程序设计 2】无锁的对象引用:AtomicReference

    AtomicReference和AtomicInteger非常类似,不同之处就在于AtomicInteger是对整数的封装,而AtomicReference则对应普通的对象引用.也就是它可以保证你在修 ...

  2. Java并发程序设计(十三)锁的性能优化

    锁的性能优化 一.优化注意事件 一)减少锁的持有时间 只在必要时进行同步,能明显减少锁的持有时间. 二)锁的细化 缺陷:当系统需要全局锁时,其消耗的资源会比较多. 三)锁的分离 比如读写分离锁 四)锁 ...

  3. Java并发基础:了解无锁CAS就从源码分析

    https://segmentfault.com/a/1190000015881923

  4. Java并发程序设计(一) 基础概念

    Java并发程序设计(一) 基础概念 一.必须知道的几个概念 一)同步(Synchronous)和异步(Asynchronous) 同步:同步方法调用一旦开始,调用者必须等到方法调用返回后,才能继续后 ...

  5. Java并发编程实战 03互斥锁 解决原子性问题

    文章系列 Java并发编程实战 01并发编程的Bug源头 Java并发编程实战 02Java如何解决可见性和有序性问题 摘要 在上一篇文章02Java如何解决可见性和有序性问题当中,我们解决了可见性和 ...

  6. java并发笔记之synchronized 偏向锁 轻量级锁 重量级锁证明

    警告⚠️:本文耗时很长,先做好心理准备 本篇将从hotspot源码(64 bits)入手,通过分析java对象头引申出锁的状态:本文采用大量实例及分析,请耐心看完,谢谢   先来看一下hotspot的 ...

  7. Java并发编程:synchronized和锁优化

    1. 使用方法 synchronized 是 java 中最常用的保证线程安全的方式,synchronized 的作用主要有三方面: 确保线程互斥的访问代码块,同一时刻只有一个方法可以进入到临界区 保 ...

  8. java并发笔记之证明 synchronized锁 是否真实存在

    警告⚠️:本文耗时很长,先做好心理准备 证明:偏向锁.轻量级锁.重量级锁真实存在 由[java并发笔记之java线程模型]链接: https://www.cnblogs.com/yuhangwang/ ...

  9. 【Java并发系列04】线程锁synchronized和Lock和volatile和Condition

    img { border: solid 1px } 一.前言 多线程怎么防止竞争资源,即防止对同一资源进行并发操作,那就是使用加锁机制.这是Java并发编程中必须要理解的一个知识点.其实使用起来还是比 ...

随机推荐

  1. 【Shell】带颜色输出(白底x色)

    echo -e "\033[31mHello World.\033[0m" 红色31m 绿色32m 黄色33m 蓝色34m 黑色30m 白色37m 紫色35m 深绿色36m

  2. HTML学习笔记08-表格

    HTML表格 表格由<table>标签来定义,表格的行由<tr>标签来定义,表格的列由<td>标签来定义 <!DOCTYPE html> <htm ...

  3. 创建虚拟机时,提示No valid host was found解决办法

    1.http://blog.csdn.net/yxwmzouzou/article/details/43892261 2.http://www.cnblogs.com/kevingrace/p/601 ...

  4. zabbix3.0监控centos当主机cpu使用率超过90%的时候报警

    在windows系统中监控cpu利用率非常容易,自带模板就有这样的功能,但是在linux里面没有默认的模板 只有cpu的负载,默认当cpu的负载在一定时间内5以上报警 cpu utilization中 ...

  5. 关于windows2008r2系统80端口被system进程占用的问题

    80端口被system占用的问题   今天启动tomcat的时候发现无法启动80端口被占用 通过netstat -ano查看,发现被pid=4的进程占用 检查进程发现是system进程pid=4给占用 ...

  6. javascript 搞不清原型链和constructor

    prototype.constructor仅仅可以用于识别对象是由哪个构造函数初始化的,仅此而已. var one=new Person(‘js’); 要解释这个结果就要仔细研究一下new这个操作符了 ...

  7. 一张纸,折多少次和珠穆拉峰一样高(for if 和break)

  8. 怎样使用github

    https://www.zhihu.com/question/20070065 https://www.shiyanlou.com/courses/868/labs/3163/document 初次尝 ...

  9. 为什么js中0.1+0.2不等于0.3,怎样处理使之相等?(转载)

    为什么js中0.1+0.2不等于0.3,怎样处理使之相等? console.log(0.1+0.2===0.3)// true or false?? 在正常的数学逻辑思维中,0.1+0.2=0.3这个 ...

  10. 优化MVC,实现数据库表的记录的添加、删除、修改、查询。

    一.在UserDAO里面重写实体user要调用的方法: 1.查询所有user表中的记录.用getAllUser()方法得到List public class UserDAO { public List ...