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. LeetCode:零钱兑换【322】【DP】

    LeetCode:零钱兑换[322][DP] 题目描述 给定不同面额的硬币 coins 和一个总金额 amount.编写一个函数来计算可以凑成总金额所需的最少的硬币个数.如果没有任何一种硬币组合能组成 ...

  2. parent

    <?php class MyObject { function myMethod() { //标准功能 echo "Standard Functionality\n"; } ...

  3. Spark- Spark基本工作原理

    Spark特点: 1.分布式 spark读取数据时是把数据分布式存储到各个节点内存中 2.主要基于内存(少数情况基于磁盘,如shuffle阶段) 所有计算操作,都是针对多个节点上内存的数据,进行并行操 ...

  4. java读取pdf文档

    import java.io.*;import org.pdfbox.pdmodel.PDDocument;import org.pdfbox.pdfparser.PDFParser;import o ...

  5. 自定义响应结构 AjaxResult()

    package com.dsj.gdbd.utils.ajax; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxm ...

  6. 代码题(3)— 最小的k个数、数组中的第K个最大元素、前K个高频元素

    1.题目:输入n个整数,找出其中最小的K个数. 例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4. 快排思路(掌握): class Solution { public ...

  7. php版微信公众平台开发之验证步骤实例详解

    本文实例讲述了php版微信公众平台开发之验证步骤.分享给大家供大家参考,具体如下: 微信公众平台开发我们现在做得比较多了,这里给各位介绍的是一个入门级别的微信公众平台验证基础知识了,有兴趣的和小编来看 ...

  8. Mybatis中collection与association的区别

    association是多对一的关系 collection是一个一对多的关系

  9. HDU 6231 (K-th Number)

    题目链接:https://cn.vjudge.net/problem/HDU-6231 思路:二分+双指针: #include <stdio.h> #include <iostrea ...

  10. (转)C协程实现的效率对比

    前段时间实现的C协程依赖栈传递参数,在开启优化时会导致错误,于是实现了一个ucontext的版本,但ucontext的切换效率太差了, 在我的机器上执行4000W次切换需要11秒左右,这达不到我的要求 ...