JAVA 重入锁 synchronized+ReentrantLock

1 重入锁:线程重复获得已经持有的锁,锁有一个"持有计数器"跟踪锁的嵌套

2 锁和条件的作用

   锁:用来保护代码片段,任何时候同一个对象只能有一个线程执行被某一个锁保护的代码

   锁:管理试图进入被保护代码片段的线程,同一对象的一个锁在同一时间只能被一个线程持有

   锁:可以拥有多个不同的条件对象

   条件对象:管理已经持有锁(已进入保护代码片段),但是不满足某个条件不能继续的线程,使其暂时放弃锁,并进入等待条件对象唤醒。

3  synchronized与ReentrantLock原理相同,synchronized是对象的内部锁并持有一个内部条件对象

4  建议共享对象的同一个成员变量的所有修改方法都要使用同一个锁。

ReentrantLock例

public class LockTest {
	
	ReentrantLock lock1=new ReentrantLock();
	ReentrantLock lock2=new ReentrantLock();
	
	public void test1() throws InterruptedException  {
		lock1.lock();
		System.out.println(Thread.currentThread().getName()+" get lock1 test1()");
		test4();//尝试获得lock2锁
		test2(); //尝试再次进入lock1锁		
		System.out.println(Thread.currentThread().getName()+" unlock lock1 test1()");	
		lock1.unlock();						
	}
	
	public void test2() throws InterruptedException {
		lock1.lock();
		System.out.println(Thread.currentThread().getName()+" get lock1 test2()");		
		System.out.println(Thread.currentThread().getName()+" unlock lock1 test2()");
		lock1.unlock();
	}
	
	public void test3() throws InterruptedException {
		lock2.lock();
		System.out.println(Thread.currentThread().getName()+" get lock2 test3()");
		System.out.println(Thread.currentThread().getName()+" sleep in lock2");
		Thread.sleep(5000);			
		System.out.println(Thread.currentThread().getName()+" unlock lock2 test3()");
		lock2.unlock();
	}
	
	public void test4() throws InterruptedException {
		System.out.println(Thread.currentThread().getName()+" into test4() try get lock2");
		lock2.lock();
		System.out.println(Thread.currentThread().getName()+" get lock2 test4()");
		System.out.println(Thread.currentThread().getName()+" unlock lock2 test4()");
		lock2.unlock();
	}
	
	
	public static void main(String[] args) throws InterruptedException {
		
		LockTest lTest=new LockTest();
		
		FastWork fastWork=new FastWork(lTest);
		
		Thread t1=new Thread(fastWork, "T1");
		t1.start();
		lTest.test1();
		
	}

}

class FastWork implements Runnable{
	LockTest lTest;
	

	public FastWork(LockTest lTest) {
		super();
		this.lTest = lTest;
	}


	@Override
	public void run() {
		try {
			lTest.test3(); //尝试获得lock2锁
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
	}
	
	
}


运行结果

T1 get lock2 test3()
main get lock1 test1()
T1 sleep in lock2
main into test4() try get lock2
T1 unlock lock2 test3()
main get lock2 test4()
main unlock lock2 test4()
main get lock1 test2()
main unlock lock1 test2()
main unlock lock1 test1()

LockTest lTest时两个线程的共享对象,test1()+test2()被lock1保护,test3()+test4()被lock2保护。

1.当T1线程进入test3()获得lock2后,再T1释放lock2之前,main线程不能访问被lock2保护的所有代码片段。main线程进入test4()后,当到达lock2.lock()时阻塞了,直到T1线程放弃lock2,main线程才能继续执行test4()中被lock2保护代码片段。

2.main线程已经获得lock1,之后可以再进入其他任意lock1保护的代码片段,因为此时其他任意线程不能进入lock1保护的代码片段。重入锁的特点

3.可以看出lock1+lock2互不影响,所以建议共享对象的一个成员变量的所有修改方法都要使用同一个锁。否则两个修改方法用不同锁保护,则可能会有两个线程同时修改同一个成员变量。


synchronized客户端锁例

public class LockTest1 {

	public static void main(String[] args) throws InterruptedException {
		CountDownLatch countDownLatch=new CountDownLatch(1);
		OneTest oneTest=new OneTest();
		LockTestWork work=new LockTestWork(oneTest, countDownLatch);
		
		
		Thread t1=new Thread(work);
		t1.start();
		Thread.sleep(1000);	
		
		synchronized (oneTest) {//客户端锁		
			System.out.println(Thread.currentThread().getName()+" sleep ");
			countDownLatch.countDown(); //告诉t1 可以行动
			Thread.sleep(5000);			
		}		
	}

}

class LockTestWork implements Runnable{
	OneTest oneTest;
	CountDownLatch countDownLatch;
	
	public LockTestWork(OneTest oneTest, CountDownLatch countDownLatch) {
		super();
		this.oneTest = oneTest;
		this.countDownLatch = countDownLatch;
	}

	public LockTestWork(OneTest oneTest) {
		super();
		this.oneTest = oneTest;
	}

	@Override
	public void run() {
		try {
			countDownLatch.await();
			oneTest.setName("123");		
		} catch (InterruptedException e) {
			e.printStackTrace();
		}		
	}	
}

class OneTest{
	
	private String name="";

	public  String getName() {
		return name;
	}

	public synchronized void setName(String name) {
		System.out.println(Thread.currentThread().getName()+" get synchronized 锁 ");
		this.name = name;
	}
	
}
运行结果:

main sleep 

Thread-0 get synchronized 锁  //5秒之后

上面例子说明:

synchronized (oneTest) {} 锁的代码段,这段代码获得是oneTest对象的synchronized锁,主线程获得所以后睡眠5秒,这5秒Thread-0不能执行setName()。因为他不能获得oneTest对象的synchronized锁,所以阻塞。



posted @ 2018-03-19 21:06  sw008  阅读(139)  评论(0编辑  收藏  举报