在Java5 诞生之前,Java线程同步和协助只能使用synchronized锁机制,这种锁机制由JVM直接提供实现,所以经常又称内部锁,也称作对象监视器,由于这种锁有性能缺陷而且灵活不足,所以牛人在Java5添加了Lock接口及相关实现,为Java多线程同步与协作提供了另一种选择,当然,后来者不管功能还是性能都比前者优秀,以致有人倡导全部使用Lock抛弃synchronized。有了竞争就会迫使进步,果然Java 6对内部锁进行优化,性能大幅度提升,大部分情况下与Lock可以相媲美(但非公平竞争情况下Lock还是存在性能优势)而且JCP专家组提倡简单正常情况下使用synchronized内部锁,并称将来内部锁还会继续进行优化,所以现在synchronized还是广为使用。然而这只是性能方面,在功能方面Lock提供了更多的灵活性,如轮询锁、定时锁、可中断的锁获取、非块结构的加解锁等,并且在Java5以后的并发包中广为使用,所以学习研究Lock还是必须的。


public interface Lock {
void lock();
void unlock();
}


对于简单线程同步,Lock使用lock()方法请求并加锁,需要自己使用unlock()方法释放锁,并不需要限定代码范围,如果忘记会造成死锁,这是灵活性带来的负面影响,所以使用时都会增加try{...}finally{lock.unlock()},以保证锁的释放;synchronized在代码块范围外会自动释放锁,一开始就定义好锁定的代码范围,比较死板但可靠,另外synchronized经常用于修饰类成员方法,线程调用这种方法前需要先获得对应的锁,这种使用方式很顺手,简单明了,Lock没有这种语法。


Lock和synchronized对线程同步操作示例:

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TestLock {
    private int mCount;
    private Lock mLock;
                      
    public TestLock(){
        this.mCount = 0;
        this.mLock = new ReentrantLock();
    }
                      
    public static void main(String[] args) throws InterruptedException {
        TestLock testLock = new TestLock();
                          
        for(int i=0; i<2; i++){
            new Thread(testLock.new SThread()).start();
        }
                          
        TimeUnit.SECONDS.sleep(3);
                          
        for(int i=0; i<2; i++){
            new Thread(testLock.new LThread()).start();
        }
    }
                      
    private void increaseCount() {
        mCount++;
        System.out.println(Thread.currentThread().getName() + " do lock, count: " + mCount);
    }
                      
    private void decreaseCount() {
        mCount--;
        System.out.println(Thread.currentThread().getName() + " do unlock, count: " + mCount);
    }
                      
    private void doCountWithLSync() {
        mLock.lock();
        try{
            increaseCount();
                              
            mLock.lock();//re-enter
                              
            try{
                increaseCount();
            }
            finally{
                mLock.unlock();
                decreaseCount();
            }                            
        }
        finally{
            mLock.unlock();
            decreaseCount();
        }
    }
    private void doCountWithSSync() {
        synchronized(this){
            increaseCount();
                              
            synchronized(this){//re-enter
                increaseCount();
            }
                              
            decreaseCount();
        }
                          
        decreaseCount();
    }
    private class LThread implements Runnable{
        public void run(){
            doCountWithLSync();  
        }
    }
                      
    private class SThread implements Runnable{
        public void run(){   
            doCountWithSSync();
        }    
    }
}