使用ReentrantLock实现线程同步

在Java多线程中,可以使用synchronized关键字来实现线程之间同步互斥,但在JDK1.5中新增了ReentrantLock类也能达到同样的效果,并且在扩展功能上也更加强大,比如有嗅探锁定、多路分支通知等功能,而且在使用上也比synchronized更加灵活。

下面以一个例子来说明ReentrantLock的使用。

首先是Service类,需要被同步的类。

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

public class MyService {
    private Lock lock = new ReentrantLock();   //持有锁变量

    public void testMethod(){
        lock.lock();                      //在方法内部,第一行加锁
        for (int i=0;i<5;i++){
            System.out.println("Thread name:"+Thread.currentThread().getName()+" "+(i+1));
        }
        lock.unlock();                 //处理完成之后解锁
    }
}

线程类与测试类MyThread,创建4个线程,每个线程用同一个Service对象初始化,线程的run方法即执行service的testMethod方法。

public class MyThread extends Thread{
    private MyService service;

    public MyThread(MyService service){
        super();
        this.service = service;
    }
    @Override
    public void run(){
        service.testMethod();
    }
    public static void main(String[] args){
        MyService service = new MyService();
        MyThread t1 = new MyThread(service);
        MyThread t2 = new MyThread(service);
        MyThread t3 = new MyThread(service);
        MyThread t4 = new MyThread(service);

        t1.start();t2.start();t3.start();t4.start();
    }
}

程序输出如下,可以看到各个线程之间是同步执行的,一个线程执行完释放锁之后,另一个线程才能执行:

Thread name:Thread-1 1
Thread name:Thread-1 2
Thread name:Thread-1 3
Thread name:Thread-1 4
Thread name:Thread-1 5
Thread name:Thread-2 1
Thread name:Thread-2 2
Thread name:Thread-2 3
Thread name:Thread-2 4
Thread name:Thread-2 5
Thread name:Thread-0 1
Thread name:Thread-0 2
Thread name:Thread-0 3
Thread name:Thread-0 4
Thread name:Thread-0 5
Thread name:Thread-3 1
Thread name:Thread-3 2
Thread name:Thread-3 3
Thread name:Thread-3 4
Thread name:Thread-3 5

另外,当Service类多个方法(比如A、B方法)内部都调用了lock.lock()进行锁定时,当一个线程在方法A中时,另一个线程不能执行B方法。也就是说lock跟synchronized方法一样,调用lock.lock()的线程持有的是“对象锁”(对象监视器)。同一个时刻,只能有一个线程获得对象锁。

关于Lock其他使用如下:

1、公平性与不公平性
锁Lock分为“公平锁”与“不公平锁”,公平锁表示线程获取锁的顺序是按照线程加锁的顺序分配的,机先来先得的FIFO顺序。而不公平锁就是一种获取锁的抢占机制,是随机获得锁的,和公平锁不一样的就是先来的不一定先得到锁。
在锁的构造函数中有一个如下:

 //创建一个具有给定公平策略的 ReentrantLock。
ReentrantLock(boolean fair) 

2、方法getHoldCount()
方法getHoldCount()的作用是查询当前线程保持此锁定的个数,也就是调用lock()方法的次数。使用方法为:

try{
    lock.lock();
    System.out.println(lock.getHoldCount());
    serviceMethod();
}finally{
    lock.unlock();
}

3、方法getQueueLength()的作用是返回正等待获取此锁定的线程估计数。

4、方法getWaitQueueLength(Condition condition)的作用是返回等待此锁定相关的给定条件Condition的线程估计数,比如有5个线程,每个线程都执行了同一个condition对象的await()方法,则调用getWaitQueueLength(Condition)方法时返回的int值是5.

5、方法lockInterruptibly()的作用是:如果当前线程未被中断,则获取锁定,如果已经被中断则出现异常
方法boolean tryLock()的作用是,仅在调用时锁定未被另一个线程保持的情况下,才获取该锁定。
方法boolean tryLock(long timeout,TimeUnit unit)的作用是,如果锁定在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁定。

参考《Java多线程编程核心技术》

lock 必须在 finally 块中释放。否则,如果受保护的代码将抛出异常,锁就有可能永远得不到释放!这一点区别看起来可能没什么,但是实际上,它极为重要。忘记在 finally 块中释放锁,可能会在程序中留下一个定时炸弹,当有一天炸弹爆炸时,您要花费很大力气才有找到源头在哪。而使用同步,JVM 将确保锁会获得自动释放。
参考:Java 理论与实践: JDK 5.0 中更灵活、更具可伸缩性的锁定机制http://www.ibm.com/developerworks/cn/java/j-jtp10264/index.html

2016.8.9读《实战java高并发程序设计》添加:
1. ReentrantLock称为“可重入锁”,是因为一个线程可以获得多次锁,每次获取锁时都将引用计数增加1。
2. ReentrantLock有个方法lockInterruptibly(),这个方法获取锁,并且自带了相应中断的能力.
3. 重入锁可以使用trylock方法,非阻塞的尝试获取锁。
4. 重入锁有构造方法public ReentrantLock(boolean fair)可以保证线程获取锁时的公平性,但是性能有影响。
5. ReadWriteLock也应该算是一个优点吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值