使用synchronized 实现ReentrantLock(美团面试题目)

    刚看到这个题目的时候无从下手,由于以为synchronized和lock在加锁的方式上有很大不一样,好比,看看正常状况下synchronized时如何加锁的。java

        方式一: 框架

public synchronized void a(){  
    //TODO  
}  

        方式二: dom

public void b(){  
    synchronized(this){  
        //TODO  
    }  
} 

 

        从这两种方式来看,锁都是加在{}之间的,咱们再来看看Lock是如何作的呢: ide

public void c() {  
    lock.lock();  
    try {  
        // TODO  
    } finally {  
        lock.unlock();  
    }  
}  

         这种方式的锁是加在lock() 和unlock()之间的,因此要想实现一个lock功能,就要想怎么实现这样两个方法,lock()和unlock()方法,先定义一个框架以下所示: ui

public void lock(){        
}    
public void unlock(){        
}   

        而后要想怎么用synchronized去实现这两个方法。 this

        如今其实只是稍微清楚了一点思路,可是还不知道怎么去填充这两个方法,这是后再来分析一下Lock的加锁有什么特色,再来看看这段代码:spa

public void c() {  
    lock.lock();//When current thread get the lock, other thread has to wait  
    try {  
        //current thread get in the lock, other thread can not get in  
        // TODO  
    } finally {  
        lock.unlock();//current thread release the lock  
    }  
}  

         这段代码我只是加了一点注释,别的什么都没有作,是否是帮助理解这段代码,看看出现频率最高的词是什么,是current thread,那么咱们去填充lock()和unlock()方法的时候是否是注意要抓住current thread这个关键字就能够找到解决方案呢?答案是确定的。 线程

        接着分析,使用synchronized的时候如何让线程等待呢?是用wait()方法。怎么让线程唤醒呢,是用notify()方法。那么就要在lock()方法中使用wait()方法,在unlock()方法中使用notify()方法。那么咱们在使用wait()和notify()的时候是有一个条件的,想一想咱们应该使用什么做为条件呢?code

        咱们应该使用当前锁是否被占用做为判断条件,若是锁被占用,current thread等待,想一想咱们在使用synchronized的时候是否是一直使用的这个条件,答案也是确定的。orm

        再来分析一下何时释放锁,使用什么做为条件,想一想若是线程A拿到了锁,线程B能释放吗?固然不能,若是B能释放就违反了原则,固然不能。确定是A线程的锁只能A来释放。因此判断条件就是判断持有锁的线程是否是current thread,若是是的话,能够释放,不是的话固然不能。

        如今来看看完整的代码:网上写的有点乱,我本身重新整理了一下,而且能够正常运行  

package test_lock;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

public class NaiveLock {
    
    private static final long NONE=-1;
    private long owner =NONE;
    
    public synchronized void lock(){
        long currentThreadId=Thread.currentThread().getId();
        if(owner==currentThreadId){
            throw new IllegalStateException("lock has been acquired by current thread");
        }
        
        while(this.owner!=NONE){
            
            System.out.println(String.format("thread %s is waiting lock", currentThreadId));
            try {
                wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        this.owner=currentThreadId;
        System.out.println(String.format("lock is acquired by thread %s", currentThreadId));
        
    }
    
    public synchronized void unlock(){
        
        long currentThreadId=Thread.currentThread().getId();
        
        if(this.owner!=currentThreadId){
            throw new IllegalStateException("Only lock owner can unlock the lock");
        }
        
        System.out.println(String.format("thread %s is unlocking", owner));
        owner=NONE;
        notify();
        
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        final NaiveLock lock=new NaiveLock();
        ExecutorService executor= Executors.newFixedThreadPool(20, new ThreadFactory(){
             private ThreadGroup group =new ThreadGroup("test thread group");
             {
             group.setDaemon(true);
             }
            @Override
            public Thread newThread(Runnable r) {
                // TODO Auto-generated method stub
                return new Thread(group,r);
            }});
        
        
        for(int i=0;i<20;i++){
            executor.submit(new Runnable(){

                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    lock.lock();
                    System.out.println(String.format("thread %s is running...", Thread.currentThread().getId()));
                    
                    
                    try {
                        Thread.sleep(new Random().nextInt(1000));
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    lock.unlock();
                }});
        }
        

    }

}

结果为:

lock is acquired by thread 10
thread 10 is running...
thread 29 is waiting lock
....
thread 13 is running... thread 13 is unlocking lock is acquired by thread 12 thread 12 is running... thread 12 is unlocking
相关文章
相关标签/搜索