首先向Doug Lea致敬。

CLH

以下是CLH锁的一个简单实现:

class SimpleCLHLock {
/**
* initialized with a dummy node
*/
private Node dummy = new Node();
private AtomicReference<Node> tail = new AtomicReference<Node>(dummy); /**
* implicit single linked list node
*/
private static class Node {
public volatile boolean locked = false;
} private ThreadLocal<Node> threadLockNode = new ThreadLocal<Node>(); public void lock() {
Node last_tail;
Node new_tail = new Node();
new_tail.locked = true; while (true) {
last_tail = tail.get(); if (tail.compareAndSet(last_tail, new_tail)) {
break;
}
}
// we just keep previous tail node as current node's direct predecessor
// and waiting it jump into unlocked state, so we form a single linked list implicitly
while (last_tail.locked) {
Thread.yield();
} // we need the node reference when we want to unlock
// some threads may waiting on its state to be unlocked in above while-loop statement.
threadLockNode.set(new_tail);
} public void unlock() {
// retrieve the lock state held by current thread
Node node = threadLockNode.get();
// if null then the current thread has not own the lock, also can't perform unlock operation
if (node == null) {
throw new IllegalMonitorStateException();
}
node.locked = false;
threadLockNode.set(null);
}
}

测试了不同的同步方式的速度

package lock;

import java.util.List;

import java.util.ArrayList;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantLock; /**
* Created by hegaofeng on 6/30/15.
*/
public class CLH {
private static volatile long count; private static AtomicLong atomicLong = new AtomicLong(); private static ExecutorService pool = Executors.newCachedThreadPool(); public static void main(String[] args) { final int deltaPerThreads = 10000;
final int numsOfThreads = 10; Callable<Boolean> raw_counter = new Callable<Boolean>() {
@Override
public Boolean call() {
for (int i=0; i<deltaPerThreads; i++) count++;
return true;
}
}; Callable<Boolean> syn_counter = new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
for (int i=0; i<deltaPerThreads; i++) {
synchronized (CLH.class) {
count++;
}
} return true;
}
}; Callable<Boolean> clh_counter = new Callable<Boolean>() {
private SimpleCLHLock lock = new SimpleCLHLock();
@Override
public Boolean call() throws Exception {
for (int i=0; i<deltaPerThreads; i++) {
lock.lock();
count++;
lock.unlock();
}
return true;
}
}; final Callable<Boolean> lck_counter = new Callable<Boolean>() {
private ReentrantLock lock = new ReentrantLock();
@Override
public Boolean call() throws Exception {
for (int i=0; i<deltaPerThreads; i++) {
lock.lock();
count++;
lock.unlock();
}
return true;
}
}; final Callable<Boolean> lck_fair_counter = new Callable<Boolean>() {
private ReentrantLock lock = new ReentrantLock(true);
@Override
public Boolean call() throws Exception {
for (int i=0; i<deltaPerThreads; i++) {
lock.lock();
count++;
lock.unlock();
}
return true;
}
}; Callable<Boolean> sem_counter = new Callable<Boolean>() {
private Semaphore sem = new Semaphore(1);
@Override
public Boolean call() throws Exception {
for(int i=0; i<deltaPerThreads; i++) {
sem.acquire();
count++;
sem.release();
}
return true;
}
}; Callable<Boolean> sem_fair_counter = new Callable<Boolean>() {
private Semaphore sem = new Semaphore(1, true);
@Override
public Boolean call() throws Exception {
for(int i=0; i<deltaPerThreads; i++) {
sem.acquire();
count++;
sem.release();
}
return true;
}
}; Callable<Boolean> cas_counter = new Callable<Boolean>() {
private AtomicBoolean locked = new AtomicBoolean();
@Override
public Boolean call() throws Exception {
for (int i=0; i<deltaPerThreads; i++) {
while (true) {
if (locked.compareAndSet(false, true)) {
count++;
locked.getAndSet(false);
break;
}
}
}
return true;
}
}; Callable<Boolean> pure_cas = new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
for (int i=0; i<deltaPerThreads; i++) {
atomicLong.incrementAndGet();
}
return true;
}
}; test("raw", raw_counter, deltaPerThreads, numsOfThreads); test("syn", syn_counter, deltaPerThreads, numsOfThreads); test("CLH", clh_counter, deltaPerThreads, numsOfThreads); test("lock", lck_counter, deltaPerThreads, numsOfThreads); test("lock_fair", lck_fair_counter, deltaPerThreads, numsOfThreads); test("sem", sem_counter, deltaPerThreads, numsOfThreads); test("sem_fair", sem_fair_counter, deltaPerThreads, numsOfThreads); test("CAS", cas_counter, deltaPerThreads, numsOfThreads); test("pure_CAS", pure_cas, deltaPerThreads, numsOfThreads);
} public static void test(String name, Callable<Boolean> callable, final int deltaPerThreads, final int numsOfThreads) {
count = 0;
atomicLong.set(0);
pool = Executors.newCachedThreadPool(); List<Callable<Boolean>> calls = new ArrayList<Callable<Boolean>>();
for (int i=0; i<numsOfThreads; i++) {
calls.add(callable);
}
long start = System.nanoTime();
try {
pool.invokeAll(calls);
} catch (InterruptedException e) {
e.printStackTrace();
}
pool.shutdown();
long end = System.nanoTime();
System.out.println("case : " + name);
System.out.println("counted: " + (name.equals("pure_CAS") ? atomicLong.get() : count));
System.out.println("target : " + numsOfThreads * deltaPerThreads);
System.out.println("time : " + (end - start) / 1e6 + "ms");
System.out.println();
}
}

结果:

case   : raw
counted: 79270
target : 100000
time : 11.278ms case : syn
counted: 100000
target : 100000
time : 13.553ms case : CLH
counted: 100000
target : 100000
time : 1037.665ms case : lock
counted: 100000
target : 100000
time : 29.134ms case : lock_fair
counted: 100000
target : 100000
time : 638.944ms case : sem
counted: 100000
target : 100000
time : 45.154ms case : sem_fair
counted: 100000
target : 100000
time : 552.855ms case : CAS
counted: 100000
target : 100000
time : 158.422ms case : pure_CAS
counted: 100000
target : 100000
time : 31.964ms
  • raw 表示不进行任何同步,现在没有保护的情况下计数累加产生了错误
  • syn 表示使用内置锁同步方式即使用synchronized块,在几种方式里表现最好
  • CLH 表示使用自己实现的一个CLH锁(具有排队功能的自旋锁),这里的CLH的实现方式决定了它是一个公平锁
  • lock 表示用ReentrantLock进行数据保护,速度仅次于内置锁,lock_fair是它的公平版本,不过速度上有大幅下降,变慢了将近20倍
  • sem 表示使用Semaphore也就是信号量进行数据保护,速度也不错,sem_fair是它的公平版本,和ReentrantLock上出现的情况一样,公平版本比非公平版本出现了大幅的速度下降,慢了10倍
  • CAS 用CAS操作实现简单的自旋锁,不具有排队功能
  • pure_CAS 表示直接用使用AtomicLong类型的count变量进行计数,就不需要锁保护了,速度也是非常快得

调整测试的参数将线程数改为2,每线程增量改为50000即总增量不变的情况下得到的结果如下:


case : raw
counted: 91460
target : 100000
time : 4.767ms case : syn
counted: 100000
target : 100000
time : 12.385ms case : CLH
counted: 100000
target : 100000
time : 86.12ms case : lock
counted: 100000
target : 100000
time : 33.91ms case : lock_fair
counted: 100000
target : 100000
time : 108.119ms case : sem
counted: 100000
target : 100000
time : 62.503ms case : sem_fair
counted: 100000
target : 100000
time : 83.035ms case : CAS
counted: 100000
target : 100000
time : 13.528ms case : pure_CAS
counted: 100000
target : 100000
time : 11.377ms

基本锁

ReentrantLock的非公平版本在两次测试中并没有很大的变化,比较稳定。

公平锁

在不必要的情况下不去使用锁或者信号量的公平版本,它们相比非公平版本要慢很多,尤其当竞争非常激烈时。从第二组数据来看公平锁与非公平锁的差距缩小了很多,因为在竞争程度比较低(线程数少)的时候花在维护队列上的时间将大大减少。

CAS

正如Java并发编程中提到的CAS在高竞争的环境下性能不如直接使用锁,因为当竞争非常激烈时CAS花在重试上的时间将会大量增加(因为竞争激烈变量变化越快,CAS操作失败可能性越大)。而在竞争不是非常激烈的情况下CAS的开销更小,比如在第二次此时中的CAS自旋锁时间就比直接用ReentrantLock来得少。

内置锁

虽然说在Java并发编程一书中提到JDK1.6的Lock实现比synchronized要略快,这在JDK1.7中恐怕已经不成立了。

AbstractQueuedSynchronizer

http://javarticles.com/2012/10/abstractqueuedsynchronizer-aqs.html#prettyPhoto

JAVA 并发:CLH 锁 与 AbstractQueuedSynchronizer的更多相关文章

  1. java并发编程 | 锁详解:AQS,Lock,ReentrantLock,ReentrantReadWriteLock

    原文:java并发编程 | 锁详解:AQS,Lock,ReentrantLock,ReentrantReadWriteLock 锁 锁是用来控制多个线程访问共享资源的方式,java中可以使用synch ...

  2. 从源码学习Java并发的锁是怎么维护内部线程队列的

    从源码学习Java并发的锁是怎么维护内部线程队列的 在上一篇文章中,凯哥对同步组件基础框架- AbstractQueuedSynchronizer(AQS)做了大概的介绍.我们知道AQS能够通过内置的 ...

  3. Java并发编程锁系列之ReentrantLock对象总结

    Java并发编程锁系列之ReentrantLock对象总结 在Java并发编程中,根据不同维度来区分锁的话,锁可以分为十五种.ReentranckLock就是其中的多个分类. 本文主要内容:重入锁理解 ...

  4. java 并发多线程 锁的分类概念介绍 多线程下篇(二)

    接下来对锁的概念再次进行深入的介绍 之前反复的提到锁,通常的理解就是,锁---互斥---同步---阻塞 其实这是常用的独占锁(排它锁)的概念,也是一种简单粗暴的解决方案 抗战电影中,经常出现为了阻止日 ...

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

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

  6. Java并发编程锁之独占公平锁与非公平锁比较

    Java并发编程锁之独占公平锁与非公平锁比较 公平锁和非公平锁理解: 在上一篇文章中,我们知道了非公平锁.其实Java中还存在着公平锁呢.公平二字怎么理解呢?和我们现实理解是一样的.大家去排队本着先来 ...

  7. Java并发编程-再谈 AbstractQueuedSynchronizer 1 :独占模式

    关于AbstractQueuedSynchronizer JDK1.5之后引入了并发包java.util.concurrent,大大提高了Java程序的并发性能.关于java.util.concurr ...

  8. 【Java并发】详解 AbstractQueuedSynchronizer

    前言 队列同步器 AbstractQueuedSynchronizer(以下简称 AQS),是用来构建锁或者其他同步组件的基础框架.它使用一个 int 成员变量来表示同步状态,通过 CAS 操作对同步 ...

  9. Java并发——显示锁

    Java提供一系列的显示锁类,均位于java.util.concurrent.locks包中. 锁的分类: 排他锁,共享锁 排他锁又被称为独占锁,即读写互斥.写写互斥.读读互斥. Java的ReadW ...

随机推荐

  1. UVA10829 L-Gap Substrings(后缀数组+ST表)

    后缀数组+ST表. 代填的坑. \(Code\ Below:\) #include <bits/stdc++.h> #define ll long long using namespace ...

  2. Linux巩固记录(2) java项目的编译和执行

    由于要近期使用hadoop等进行相关任务执行,操作linux时候就多了 以前只在linux上配置J2EE项目执行环境,无非配置下jdk,部署tomcat,再通过docker或者jenkins自动部署上 ...

  3. 修改oracle默认监听端口

    修改oracle默认监听端口 oracle端口修改 主要是修改两个文件和修改oracle参数local_listener 1 查看当前监听状态 [oracle@test ~]$ lsnrctl sta ...

  4. Postgres 的 Array 类型

    mysql 不支持 Array 类型 一.Postgres 原生SQL 适用场景:可以用于实现贴标签功能 1.定义 CREATE TABLE "Students" ( name V ...

  5. Python中Flask框架SQLALCHEMY_ECHO设置

    在用配置类的方式给app设置配置时, SQLALCHEMY_ECHO 这个是记录打印SQL语句用于调试的, 一般设置为False, 不然会在控制台输出一大堆的东西 /home/python/.virt ...

  6. C# 发送HTTP请求超时解决办法

    request.GetResponse();超时问题的解决,和HttpWebRequest多线程性能问题,请求超时的错误, 解决办法 1.将http的request的keepAlive设置为false ...

  7. Oracle RAC 环境下的连接管理(转) --- 防止原文连接失效

    崔华老师的文章!!! 这篇文章详细介绍了Oracle RAC环境下的连接管理,分别介绍了什么是 Connect Time Load Balancing.Runtime Connection Load ...

  8. 线程同步辅助类CyclicBarrier

    CyclicBarrier 是一个可重置的多路同步点,在某些并行编程风格中很有用. 集合点同步:CyclicBarrier 多条线程同时执行一个阶段性任务时,相互等待,等到最后一个线程执行完阶段后,才 ...

  9. (转)Python3.5 queue模块详解

    原文:https://www.cnblogs.com/CongZhang/p/5274486.html queue介绍 queue是python中的标准库,俗称队列,可以直接import 引用,在py ...

  10. 前端组件化Polymer入门教程(1)——初识&&安装

    前端组件化Polymer入门教程目录: 前端组件化Polymer入门教程(1)--初识&&安装 前端组件化Polymer入门教程(2)--快速入门 前端组件化Polymer入门教程(3 ...