`
liujiahaogood
  • 浏览: 26138 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

ReentrantLock和内部锁的性能对比【转】

阅读更多

 ReentrantLock是jdk5引入的新的锁机制,它与内部锁(synchronize) 相同的并发性和内存语义,比如可重入加锁语义。在中等或者更高负荷下,ReentrantLock有更好的性能,并且拥有可轮询和可定时的请求锁等高级功能。这个程序简单对比了ReentrantLock公平锁、ReentrantLock非公平锁以及内部锁的性能,从结果上看,非公平的ReentrantLock表现最好。内部锁也仅仅是实现统计意义上的公平,结果也比公平的ReentrantLock好上很多。这个程序仅仅是计数,启动N个线程,对同一个Counter进行递增,显然,这个递增操作需要同步以保证原子性,采用不同的锁来实现同步,然后查看结果。
Counter接口:

package net.rubyeye.concurrency.chapter13;

public interface Counter {
    
public long getValue();

    
public void increment();

}


然后,首先使用我们熟悉的synchronize来实现同步:

package net.rubyeye.concurrency.chapter13;

public class SynchronizeBenchmark implements Counter {
    
private long count = 0;

    
public long getValue() {
        
return count;
    }

    
public synchronized void increment() {
        count
++;
    }
}


采用ReentrantLock的版本,切记要在finally中释放锁,这是与synchronize使用方式最大的不同,内部锁jvm会自动帮你释放锁,而ReentrantLock需要你自己来处理。

package net.rubyeye.concurrency.chapter13;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockBeanchmark implements Counter {

    
private volatile long count = 0;

    
private Lock lock;

    
public ReentrantLockBeanchmark() {
        
// 使用非公平锁,true就是公平锁
        lock = new ReentrantLock(false);
    }

    
public long getValue() {
        
// TODO Auto-generated method stub
        return count;
    }

    
public void increment() {
        lock.lock();
        
try {
            count
++;
        } 
finally {
            lock.unlock();
        }
    }

}


    写一个测试程序,使用CyclicBarrier来等待所有任务线程创建完毕以及所有任务线程计算完成,清单如下:

package net.rubyeye.concurrency.chapter13;

import java.util.concurrent.CyclicBarrier;

public class BenchmarkTest {
    
private Counter counter;

    
private CyclicBarrier barrier;

    
private int threadNum;

    
public BenchmarkTest(Counter counter, int threadNum) {
        
this.counter = counter;
        barrier 
= new CyclicBarrier(threadNum + 1); //关卡计数=线程数+1
        this.threadNum = threadNum;
    }

    
public static void main(String args[]) {
        
new BenchmarkTest(new SynchronizeBenchmark(), 5000).test();
        
//new BenchmarkTest(new ReentrantLockBeanchmark(), 5000).test();
        //new BenchmarkTest(new ReentrantLockBeanchmark(), 5000).test();   
    }

    
public void test() {
        
try {
            
for (int i = 0; i < threadNum; i++) {
                
new TestThread(counter).start();
            }
            
long start = System.currentTimeMillis();
            barrier.await(); // 等待所有任务线程创建
            barrier.await(); // 等待所有任务计算完成
            long end = System.currentTimeMillis();
            System.out.println(
"count value:" + counter.getValue());
            System.out.println(
"花费时间:" + (end - start) + "毫秒");
        } 
catch (Exception e) {
            
throw new RuntimeException(e);
        }
    }

    
class TestThread extends Thread {
        
private Counter counter;

        
public TestThread(final Counter counter) {
            
this.counter = counter;
        }

        
public void run() {
            
try {
                barrier.await();
                
for (int i = 0; i < 100; i++)
                    counter.increment();
                barrier.await();
            } 
catch (Exception e) {
                
throw new RuntimeException(e);
            }
        }
    }
}

 


分别测试一下,

将启动的线程数限定为500,结果为:
公平ReentrantLock:      210 毫秒
非公平ReentrantLock :   39  毫秒
内部锁:                          39 毫秒

将启动的线程数限定为1000,结果为:
公平ReentrantLock:      640 毫秒
非公平ReentrantLock :   81 毫秒
内部锁:                           60 毫秒

线程数不变,test方法中的循环增加到1000次,结果为:
公平ReentrantLock:      16715 毫秒
非公平ReentrantLock :   168 毫秒
内部锁:                           639  毫秒

将启动的线程数增加到2000,结果为:
公平ReentrantLock:      1100 毫秒
非公平ReentrantLock:   125 毫秒
内部锁:                           130 毫秒

将启动的线程数增加到3000,结果为:
公平ReentrantLock:      2461 毫秒
非公平ReentrantLock:   254 毫秒
内部锁:                           307 毫秒

启动5000个线程,结果如下:
公平ReentrantLock:      6154  毫秒
非公平ReentrantLock:   623   毫秒
内部锁:                           720 毫秒

 

非公平ReentrantLock和内部锁的差距,在jdk6上应该缩小了,据说jdk6的内部锁机制进行了调整

 

分享到:
评论

相关推荐

    Java 多线程与并发(11-26)-JUC锁- ReentrantLock详解.pdf

    ReentrantLock的内部类Sync继承自AQS,进一步分为FairSync(公平锁)和NonfairSync(非公平锁)两个子类。公平锁确保线程按照它们请求锁的顺序获取锁,而非公平锁则不保证这种顺序,可能会有线程插队获取锁。 **...

    【并发编程】简单化理解AQS和ReentrantLock.pdf

    - **性能对比**:比较`ReentrantLock`与`synchronized`关键字在特定场景下的性能差异。 ### 结论 AQS和`ReentrantLock`是Java并发编程中重要的组成部分,通过对它们的理解和掌握,可以更好地设计和实现高性能的...

    笔记-4、显式锁和AQS1

    5. **公平性和非公平性**:ReentrantLock提供了公平锁和非公平锁的选择。公平锁确保按照请求顺序分配锁,非公平锁则不保证,通常非公平锁的性能更高,因为它减少了线程调度的开销。 **读写锁(ReadWriteLock)和...

    HashMap与CorruntHashMap性能对比

    这篇文章将深入探讨这两个类的性能对比及其背后的原理。 `HashMap`是Java集合框架中的基础类,首次出现在JDK 1.2版本中,主要用于非线程安全的场景。它的核心实现基于开放寻址法和链表,通过数组和链表的结合来存储...

    并发编程过程中常用的原子锁和场景解答和模拟

    2. **可重入锁(ReentrantLock)**:是Java `java.util.concurrent.locks`包提供的锁,它具有与内置锁相似的功能,但提供了更高级的特性,如公平锁、非公平锁、尝试锁、定时锁和条件变量等。 3. **读写锁...

    Java面试题并发部分.docx

    Java中的`synchronized`关键字和`ReentrantLock`类是悲观锁的代表。 3. **自旋锁与适应性自旋锁**: - **自旋锁**:当一个线程尝试获取已被其他线程持有的锁时,它不会立即阻塞,而是循环地检查锁是否可用,这就是...

    java面试讲题汇总-word可打印版

    67. Synchronized与ReentrantLock对比,Synchronized是内置锁,使用简单,ReentrantLock提供了更细粒度的控制,如公平锁、可中断锁、tryLock等。 68. ReentrantLock的可重入性源于持有锁的线程再次请求锁时不会阻塞...

    04、多线程(68题)1

    线程是操作系统调度的基本单位,它是进程...基于AQS的类如`ReentrantLock`、`Semaphore`等,都利用AQS的抽象方法和内部状态来实现各自的同步逻辑。AQS解决了锁和同步器的许多底层实现细节,简化了开发同步组件的工作。

    Java concurrency之公平锁(一)_动力节点Java学院整理

    ReentrantLock的内部结构包含一个Sync对象,Sync是AQS的子类,进一步分为FairSync(公平锁)和NonFairSync(非公平锁)两个子类。 6. **获取公平锁的过程** 当线程调用ReentrantLock的`lock()`方法时,实际是调用...

    Java程序性能优化之二十三个建议

    10. **使用适当的同步机制**:避免使用synchronized关键字的全局锁,可以考虑使用ReentrantLock、ConcurrentHashMap等并发容器,以减少锁竞争。 11. **使用流式API (Stream API)**:Java 8引入的流API可以简化处理...

    java面试题大全 有中兴华为内部资料, 内容真实,

    3. Lock接口:理解ReentrantLock、Condition等高级锁的用法。 4. 线程池:了解ExecutorService、ThreadPoolExecutor和ScheduledExecutorService的使用。 五、IO与NIO篇 1. 文件操作:掌握File类的使用,进行文件的...

    并发编程以及计算机底层原理

    ReentrantLock是可重入的互斥锁,支持公平和非公平策略。 4. **并发集合**:`03-并发List、Set、ConcurrentHashMap底层原理剖析-monkey`涵盖了Java并发集合的讨论。ConcurrentHashMap是一种线程安全的哈希映射表,...

    java 企业面试题

    - Lock接口与ReentrantLock:理解锁的高级特性,如公平锁、非公平锁、可重入锁。 8. **IO与NIO** - 流的概念:理解字节流和字符流的区别,以及InputStream、OutputStream、Reader、Writer家族。 - 文件操作:...

    不可不说的Java"锁"事1

    `Unsafe`是一个内部类,提供了直接内存访问和一些底层操作,如CAS。`AtomicInteger`的`incrementAndGet()`方法就是一个典型的例子,它通过`unsafe.getAndAddInt()`实现自增,这个过程就是基于CAS操作的。 3. **ABA...

    synchronize.pdf

    5. Synchronized 和 Volatile 关键字的比较:volatile 关键字是另一个用于控制内存可见性的关键字,它保证了变量的可见性,即对一个volatile变量的读总是能获取到最新的写入值。尽管volatile提供了某些同步的特性,...

    ConcurrentHashMap的实现原理(JDK1.7和JDK1.8).pdf

    每个Segment继承自`ReentrantLock`,因此可以独立加锁和解锁。 JDK1.7的`ConcurrentHashMap`结构: 1. **Segment**:类似于HashMap,由Entry数组和链表组成。每个Segment包含一个锁,用于控制对相应数据段的访问。 ...

    juc源码视频教程最全

    3. ReentrantLock与synchronized的对比,以及如何选择合适的锁策略。 4. 并发容器的线程安全实现及性能优化技巧。 5. 原子变量的无锁编程实践和效率分析。 6. 同步工具类在多线程协调中的应用案例。 7. Future和...

Global site tag (gtag.js) - Google Analytics