1 无锁

(1) cas (compare and swap) 设置值的时候,会比较当前值和当时拿到的值是否相同,如果相同则设值,不同则拿新值重复过程;注意,在设置值的时候,取值+比较+设值 是一条cpu语句,在这个过程中不会有其他线程干扰,是原子操作。从指令层面保证操作可靠。CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。

(2)无锁类 无锁算法都处于无限循环之内,先进行compare,成功后swap,不成功则一只循环compare。

AtomicInteger get() set() getAndIncrement() incrementAndGet() compareAndSet().... 封装了一个volatile的int value,以incrementAndGet()为例,会使用当前值,偏移量,和期望值做判断是否increament;getAndIncreament() 拿到值以后再加一,用当前值和期望值比较 如果相同则没被其他线程打扰,不同则重试。

AtomicReference 使用:如a= new AtomicReference("a") ,多线程调用compareAndSet("a","bc") 那么会使用cas给a对象新的引用,只有一个线程会修改成功(因为成功之后原始引用就变了 compare会失败),防止并发修改引用。

AtomicStampedReference stamped是时间戳,对atomicReference的加强。如果一个引用,经过了A→B→A的过程,一个线程在赋值进行cas的时候,compare得到后面一个A,认为没有变化于是set,这种情况对注重结果的义务没影响,但是对于过程敏感(需要记录过程变化的业务)的情况相当于忽略了一个变化过程。针对后一种情况,在每个引用改变的时候再加个时间戳,可以标注引用的变化情况,compare的时候即比较原始值又比较时间戳,失败的话重新拿值。

AtomicIntegerArray int型数组,每个元素都是cas线程安全的。

AtomicIntegerFieldUpdater 让普通变量也可以原子操作,.newUpdater(xxx.class,"字段名称") 新建更新器,用反射对某个类的某个字段使用原子操作,同时需要手动对该变量加上volatile关键字,使用更新器的increamentAndGet可以实现对该变量的原子操作。

*范例 vector 是加锁同步工具类,整体加锁。可以设计一个无锁vector,LockFreeVector. 内部封装一个AtomicReference<AtomicReference> 二维数组,当数据扩充的时候,直接在二维位置上加一个容量大一倍的数组,而不是像一般vector一样声明一个两倍大小的空数组再拷贝原来数据。相当于拥有好多个buckets,每个bucket大小都是前一个的两倍,总共30个bucket,绝对够用。扩容时,使用compareAndSet 期望原始值是null,新值是新的长度两倍的数组。add的时候 先算出应该在哪个bucket和bucket上那个位置,然后还是cas,期望原始值是null实际值为新值。

2 并发包 concurrent

(1)ReentrantLock sychronized升级版,lock=new ReentrantLock; lock.lock();lock.unlock();需要程序控制何时释放锁,增强灵活性;

可重入,可以多次lock(),lock几次就得unlock几次,每次重入lock值+1。

可中断,lock.lockinterruptibly(),这个函数加锁可中断,抓异常处理中断,可预防死锁。

可限时,lock.tryLock(),申请锁的时间加上限制,避免一直申请不到锁浪费时间。

公平锁,保证线程先到先得,但公平锁要处理排队,性能比一般锁差。

*synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过jdk代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中。

* 在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态;

(2)Condition 和reentrantlock成对使用,类似wait和notify,使用await()和signal(),挂起线程和唤醒,挂起释放锁,唤醒重新争夺锁。也和wait相似,抓中断异常来处理中断;如果调用awaitUninterruptibly() 则不会响应中断。原理是维护一个等待队列,把await的线程放入等待队列,让出cpu时钟,signal的时候把等待队列的第一个放入lock的执行队列。

1).await()方法是可以响应线程中断命令的;

2).await()和signal()方法在当前线程锁定了Condition对应的锁时才能使用;

3).一个锁对应多个Condition对象,每个Condition的signal()方法只通知相同Condition的await()方法,condition之间不会互相通知;

4).signal()被调用时,wait队列中的第一个对象会被唤醒,signalAll()时,wait队列中元素的全部按先入先出的顺序被唤醒;

5).如果既存在await的线程,又存在一直等待lock()的线程,当signal()的线程完成时,lock()的线程优先级比await()的线程优先级高,当所有lock()线程获取到锁并释放后,才会轮到await()线程。

(3)Semaphore 信号量,允许若干个线程进入临界区,如果信号量是1,就是普通的线程(具有排他性)。new Semaphore(5);初始化信号量个数,semp.acquire()和 semp.release()代表拿到信号量和释放信号量,如果初始信号量为1,代表只有一个线程可以进入临界区,跟普通加锁一样。信号量可以更灵活的资源分配。

(4)ReadWriteLock 允许多读单写,所有read线程是无等待并发。new ReentrantReadWriteLock(),读锁readLock(),写锁writeLock。读写互斥,读读允许。

读锁和写锁之间满足如下的约束:
1)当任一线程持有写锁或读锁时,其他线程不能获得写锁;
2)当任一线程持有写锁时,其他线程不能获取读锁;
3)多个线程可以同时持有读锁。

* 获取写锁以后不释放写锁可以继续获取读锁,但是获得读锁以后不释放获得写锁不可以。写锁可以降级为读锁,如果获得写锁在获得读锁,再释放写锁,读锁仍然持有。

(5)CountDownLatch 倒数计数器,所有线程都结束在继续某操作时可以使用。

(6)CyclicBarrier 循环栅栏,countDownLatch 是能设定一次,latch是–,完了以后就没用了,CyclicBarrier可以循环使用,计数是++。

*使用coutdownlatch,是把分散在各线程的路径最终统一到主线程(主线程await),cyclicBarrer是在各线程中await,每次await就++,到达初始设置的栅栏值后继续往下走,相当于所有参与者线程都到了(await)以后才继续往下走,使用时会抓异常防止某线程中断无法await导致其他线程都处在await状态无法往下走。

(7)LockSupport park() unPark() 挂起 继续线程,类似suspend,但是suspend有缺陷,如果resume发生在suspend之前,那么suspend挂起后会永远挂起;LockSupport如果先unPark 在park,不会挂起不动。park/unpark的设计原理核心是“许可”。park是等待一个许可。unpark是为某线程提供一个许可。如果某线程A调用park,那么除非另外一个线程调用unpark(A)给A一个许可,否则线程A将阻塞在park操作上。

java多线程无锁和工具类的更多相关文章

  1. Java多线程系列——线程阻塞工具类LockSupport

    简述 LockSupport 是一个非常方便实用的线程阻塞工具,它可以在线程内任意位置让线程阻塞. 和 Thread.suspend()相比,它弥补了由于 resume()在前发生,导致线程无法继续执 ...

  2. java多线程10:并发工具类CountDownLatch、CyclicBarrier和Semaphore

    在JDK的并发包(java.util.concurrent下)中给开发者提供了几个非常有用的并发工具类,让用户不需要再去关心如何在并发场景下写出同时兼顾线程安全性与高效率的代码. 本文分别介绍Coun ...

  3. Java并发 - (无锁)篇6

    , 摘录自葛一鸣与郭超的 [Java高并发程序设计]. 本文主要介绍了死锁的概念与一些相关的基础类, 摘录自葛一鸣与郭超的 [Java高并发程序设计]. 无锁是一种乐观的策略, 它假设对资源的访问是没 ...

  4. Java 多线程:锁(一)

    Java 多线程:锁(一) 作者:Grey 原文地址: 博客园:Java 多线程:锁(一) CSDN:Java 多线程:锁(一) CAS 比较与交换的意思 举个例子,内存有个值是 3,如果用 Java ...

  5. java多线程并发去调用一个类的静态方法安全性探讨

    java多线程并发去调用一个类的静态方法安全性探讨 转自:http://blog.csdn.net/weibin_6388/article/details/50750035   这篇文章主要讲多线程对 ...

  6. JAVA 中无锁的线程安全整数 AtomicInteger介绍和使用

    Java 中无锁的线程安全整数 AtomicInteger,一个提供原子操作的Integer的类.在Java语言中,++i和i++操作并不是线程安全的,在使用的时候, 不可避免的会用到synchron ...

  7. java中的Arrays这个工具类你真的会用吗

    Java源码系列三-工具类Arrays ​ 今天分享java的源码的第三弹,Arrays这个工具类的源码.因为近期在复习数据结构,了解到Arrays里面的排序算法和二分查找等的实现,收益匪浅,决定研读 ...

  8. JAVA多线程与锁机制

    JAVA多线程与锁机制 1 关于Synchronized和lock synchronized是Java的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码 ...

  9. Java 多线程:锁(二)

    Java 多线程:锁(二) 作者:Grey 原文地址: 博客园:Java 多线程:锁(二) CSDN:Java 多线程:锁(二) AtomicLong VS LongAddr VS Synchroni ...

随机推荐

  1. Vue-cli创建项目从单页面到多页面4 - 本地开发服务器设置代理

    前后端分离开发时,有时候会遇到跨域的情况:只在开发的时候存在跨域,项目上线后,由于配置的域名相同,跨域就会不存在. 这个时候,有两种方案可以比较快的解决: 1.利用h5的特性,使用cors,在ngni ...

  2. php匹配字符串中大写字母的位置

    变量名用的是驼峰,数据库中字段中的是下划线,现在想把userId等变量批量转换成user_id,怎么样获取大写字母在字符串中的位置?echo strtolower(preg_replace('/((? ...

  3. 事务的四大特性ACID

    ACID是指数据库事务的四大特性,是由Jim Gray在19世纪70年代后期提出的概念,1983年Andreas Reuter and Theo Härder创造了ACID这个缩略语用来描述这四大特性 ...

  4. Docker alpine 设置东八时区

    FROM alpine:3.8 RUN echo 'http://mirrors.ustc.edu.cn/alpine/v3.5/main' > /etc/apk/repositories &a ...

  5. VC2010编译时提示:转换到 COFF 期间失败: 文件无效或损坏

    有时候新安装好VS2010后编译时就提示上述错误,罗列一下从网上查找到的几种解决方案: 方案1: 点击“项目”-->“属性”--> “清单工具”, 然后选择"输入和输出’--&g ...

  6. [原创]java WEB学习笔记39:EL中的运算符号(算术运算符,关系运算符,逻辑运算符,empty运算符,条件运算符,括号运算符)

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  7. 0428 正则表达式 re模块

    复习 异常处理try except 一定要在except之后写一些提示或者处理的内容 try: '''可能会出现异常的代码'''except ValueError: '''打印一些提示或者处理的内容' ...

  8. Python3 函数 一

    什么是函数? 函数一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的,编程中的函数在英文中也有很多不同的叫法.在BASIC中叫做subroutine(子过程或子程序),在Pascal ...

  9. P4619 [SDOI2018]旧试题

    题目 P4619 [SDOI2018]旧试题 Ps:山东的题目可真(du)好(liu),思维+码量的神仙题 推式 求\(\sum_{i=1}^A\sum_{j=1}^B\sum_{k=1}^Cd(ij ...

  10. http keep-alive简解

    http协议中,客户端发送请求,服务端在接收到请求后,返回所需要的数据后可以关闭连接,这样客户端读取完数据时会返回EOF(-1),表明数据已接受完全 备注:EOF end of file 什么是kee ...