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

作者: Arvin Chen 分类: Java 来源: Break易站(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方法,解锁。总之,锁的思想就是拿多少个锁就要解决多少个锁。

  •   本文标题:Java的并发编程:利用Lock和synchronized创建一个可重入锁 - Break易站
    转载请保留页面地址:https://www.breakyizhan.com/java/6658.html

    发表笔记

    电子邮件地址不会被公开。 必填项已用*标注

    更多阅读