Locks in Java

原文:http://tutorials.jenkov.com/java-concurrency/locks.html

A lock is a thread synchronization mechanism like synchronized blocks except locks can be more sophisticated than Java’s synchronized blocks. Locks (and other more advanced synchronization mechanisms) are created using synchronized blocks, so it is not like we can get totally rid of the synchronized keyword.

Lock 是一种线程synchronization机制,类似于 synchronized代码块,但是比其更加复杂。

A Simple Lock 简单例子

直接使用synchronized代码块

public class Counter {
    private int count = 0;
    public int inc() {
        synchronized(this){
            return ++count;
        }
    }
}

使用 Lock 代替 synchronized代码块

public class Counter {
    private Lock lock = new Lock();
    private int count = 0;
    public int inc() {
        try {
            lock.lock();
            return ++count;
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }
}

Lock类的一种简单实现,不具备锁的可重入

public class Lock {
    private boolean isLocked = false;
    public synchronized void lock() throws InterruptedException {
        // 这种称为自旋锁,防止线程被莫名其妙的唤醒
        while (isLocked) {
            wait();
        }
        isLocked = true;
    }
    public synchronized void unlock() {
        isLocked = false;
        notify();
    }
}

Lock Reentrance 可重入锁

一个线程可以多次进入已经获得过锁对象的同步块。

    public class Reentrant {
        public synchronized outer() {
            inner();
        }
        public synchronized inner() {
            //do something
        }
    }

Notice how both outer() and inner() are declared synchronized, which in Java is equivalent to a synchronized(this) block. If a thread calls outer() there is no problem calling inner() from inside outer(), since both methods (or blocks) are synchronized on the same monitor object (“this”). If a thread already holds the lock on a monitor object, it has access to all blocks synchronized on the same monitor object. This is called reentrance. The thread can reenter any block of code for which it already holds the lock.

inner和outer方法等价于 synchronized(this)代码块,monitor object都是this。如果一个线程已经获得了对象锁,那么它能访问拥有同一monitor object的同步代码块,这种就称为可重入。

之前上面的Lock例子不具备可重入。

    public class Reentrant2{
        Lock lock = new Lock();
        public void outer(){
            lock.lock();
            inner();
            lock.unlock();
        }
        public synchronized inner(){
            lock.lock();
            //do something
            lock.unlock();
        }
    }

调用outer方法,lock第一次能够锁住,执行到inner方法时,线程将再次去尝试锁住lock实例,这是不会成功的,因为在outer方法中已经locked了。

原因很明显,参看Lock类的代码

    public class Lock{
        boolean isLocked = false;
        public synchronized void lock()
                throws InterruptedException{
            while(isLocked){
                wait();
            }
            isLocked = true;
        }
  ...
    }

调用inner方法时,会执行wait方法,而调用outer方法已经持有了锁,这时就会一直等待下去。
下面是改进后的Lock类。

    public class Lock{
        boolean isLocked = false;
        Thread  lockedBy = null;
        int     lockedCount = 0;
        public synchronized void lock()
                throws InterruptedException{
            Thread callingThread = Thread.currentThread();
            while(isLocked && lockedBy != callingThread){
                // 对于当前线程不在执行线程等待
                wait();
            }
            isLocked = true;
            lockedCount++;
            lockedBy = callingThread;
        }
        public synchronized void unlock(){
            if(Thread.curentThread() == this.lockedBy){
                lockedCount--;
                if(lockedCount == 0){
                    isLocked = false;
                    notify();
                }
            }
        }
  ...
    }

Lock Fairness 锁的公平性

Java’s synchronized blocks makes no guarantees about the sequence in which threads trying to enter them are granted access. Therefore, if many threads are constantly competing for access to the same synchronized block, there is a risk that one or more of the threads are never granted access - that access is always granted to other threads. This is called starvation. To avoid this a Lock should be fair. Since the Lock implementations shown in this text uses synchronized blocks internally, they do not guarantee fairness. Starvation and fairness are discussed in more detail in the text Starvation and Fairness.

Calling unlock() From a finally-clause

锁的释放应该放在finally中。

    lock.lock();
    try{
        // do somethings,which may throw exception
    } finally {
        lock.unlock();
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值