• Tags
  •         
  • www.breakyizhan.com
  •    

    Break易站已经介绍了各种锁的使用,我们可以不可以自己来创建一个MyLock.java来创建一把锁呢?其实是可以的,我们可以用实现lock接口来创建属于自己的一把锁。

    Java的并发编程:利用Lock和synchronized创建一个可重入锁

    利用Lock接口和synchronized创建一个锁

    Java的并发编程:Lock接口的认识和使用中的例子,不过创建我们自己的MyLock, 测试代码,很简单的代码,一个getNext方法,然后创建5个线程去调用,如下:

    package com.breakyizhan.thread.ta1;
    
    public class Sequence {
    
    	private MyLock lock = new MyLock();
    
    	private int value;
    
    	public int getNext() {
    		lock.lock();
    		value++;
    		lock.unlock();
    		return value;
    
    	}
    	
    	public static void main(String[] args) {
    		
    		Sequence s = new Sequence();
    		
    		new Thread(new Runnable() {
    			
    			@Override
    			public void run() {
    				while(true)
    				System.out.println(s.getNext());
    			}
    		}).start();
    		new Thread(new Runnable() {
    			
    			@Override
    			public void run() {
    				while(true)
    				System.out.println(s.getNext());
    			}
    		}).start();
    		new Thread(new Runnable() {
    			
    			@Override
    			public void run() {
    				while(true)
    				System.out.println(s.getNext());
    			}
    		}).start();
    		new Thread(new Runnable() {
    			
    			@Override
    			public void run() {
    				while(true)
    				System.out.println(s.getNext());
    			}
    		}).start();
    		new Thread(new Runnable() {
    			
    			@Override
    			public void run() {
    				while(true)
    				System.out.println(s.getNext());
    			}
    		}).start();
    	}
    
    }
    

    MyLock.java如下:

    package com.breakyizhan.thread.ta1;
    
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    
    public class MyLock implements Lock {
    	
    	private boolean isLocked = false;
    	
    
    
    	@Override
    	public synchronized void lock() {
    		while (isLocked)
    			try {
    				wait();
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    	}
    	
    	@Override
    	public synchronized void unlock() {
    				notify();
    				isLocked = false;
    	}
    
    	@Override
    	public void lockInterruptibly() throws InterruptedException {
    		
    	}
    
    	@Override
    	public boolean tryLock() {
    		return false;
    	}
    
    	@Override
    	public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
    		// TODO Auto-generated method stub
    		return false;
    	}
    
    	
    
    	@Override
    	public Condition newCondition() {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    }
    

    输出如下:

    1
    2
    3
    4
    5
    6
    ......
    

    可以看到,这个代码是没有线程安全问题的。

    利用Lock接口和synchronized创建一个可重入锁

    那么,可以用这个MyLock.java来实现可重入锁么?答案显然是不可以的,现在来测试一下,还是创建MyLock来锁住,如下:

    package com.breakyizhan.thread.ta1;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class Demo {
    	
    	private MyLock lock = new MyLock();
    	
    	public void a() {
    		lock.lock();
    		System.out.println("a");
    		b();
    		lock.unlock();
    	}
    	
    	public void b() {
    		lock.lock();
    		System.out.println("b");
    		c();
    		lock.unlock();
    	}
    	
    	
    	public static void main(String[] args) {
    		Demo d = new Demo();
    		
    		new Thread(new Runnable() {
    			
    			@Override
    			public void run() {
    				d.a();
    			}
    		}).start();
    		
    		
    	}
    
    }
    
    

    输出:

    a

    我们可以看到,控制台就是没办法打印出b来,那么,应该怎么修改呢?我们应该把锁MyLock改成如下:

    package com.breakyizhan.thread.ta1;
    
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    
    public class MyLock implements Lock {
    	
    	private boolean isLocked = false;
    	
    	private Thread lockBy = null;
    	
    	private int lockCount = 0;
    
    	@Override
    	public synchronized void lock() {
    		// ...
    		
    		Thread currentThread = Thread.currentThread(); // Thread-0
    		
    		while (isLocked && currentThread != lockBy)
    			try {
    				wait();
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		isLocked = true;
    		lockBy = currentThread;
    		lockCount ++; // 1   2
    	}
    	
    	@Override
    	public synchronized void unlock() {
    		if(lockBy == Thread.currentThread()) {
    			lockCount --;  // 1  0
    			
    			if(lockCount == 0) {
    				notify();
    				isLocked = false;
    			}
    		}
    	}
    
    	@Override
    	public void lockInterruptibly() throws InterruptedException {
    		
    	}
    
    	@Override
    	public boolean tryLock() {
    		return false;
    	}
    
    	@Override
    	public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
    		// TODO Auto-generated method stub
    		return false;
    	}
    
    	
    
    	@Override
    	public Condition newCondition() {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    }
    
    

    这样就能正常打印了,而这样也是一个可重入锁了。具体流程可以用demo这个例子说一下。进入a方法的时候,线程调用lock.lock()拿了一个锁,isLocked && currentThread != lockBy,所以isLocked 是false的,就不用wait了。然后a方法里面有b方法,b方法里面再次调用lock.lock(),但是对于条件isLocked && currentThread != lockBy,第二个条件currentThread != lockBy是false的,所以不用wait了。这个时候lockCount 是2(每调用一次lock.lock()加一次)。然后出去b方法,解锁,再出去a方法,解锁。总之,锁的思想就是拿多少个锁就要解决多少个锁。

     
    转载请保留页面地址:https://www.breakyizhan.com/java/6658.html