Synchronized锁和Lock锁有什么区别?

题目一:synchronized和Lock有什么区别?用新的Lock有什么好处?请举例说明。

1、原始构成:

        synchronized:属于JVM层面,它是java的关键字

            底层是通过monitor对象来完成的,其实wait/notify等方法也依赖于monitor对象,所以只有在synchronized同步方法或者同步代码块中才能调用wait/notify等方法;

        lock:是具体类(java.util.concurrent.locks.Lock)是api层面的锁;

2、使用方法:

        synchronized:不需要用户手动释放锁,当synchronized代码执行完后系统会自动让线程释放对锁的占用;

        ReentrantLock:则需要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象;(且上锁几次,必须解锁几次)

3、等待是否可中断:

        synchronized:不可中断,除非抛出异常或者正常运行完成;

        ReentrantLock:可中断:

                a. 设置超时方法 tryLock(Long timeout, TimeUnit unit);

                b. LockInterruptibly()放代码块中,调用interrupt()方法可中断;

4、加锁是否公平:

        synchronized:是非公平锁;

        ReentrantLock:虽然默认也是非公平锁,但是在new构造的时候,可以通过传入true,构造成公平锁;

5、锁绑定多个条件condition:

        synchronized:没有condition这种说法,要么随机唤醒一个,要么全部唤醒;

        ReentrantLock:用来实现分组唤醒需要唤醒的线程们,而且可以精确唤醒,而不是像synchronized那样;


题目二、多线程之间按顺序调用,实现A——>B——>C三个线程启动,要求如下:

AA打印5次,BB打印10次,CC打印15次

紧接着

AA打印5次,BB打印10次,CC打印15次

循环10轮;

分析:这种精确唤醒的问题,必须得使用lock方式解决;

实现代码:

package com.jiguiquan.www;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class SyncAndReentrantLockDemo {
	public static void main(String[] args) {
		//线程操纵资源类
		ShareResource shareResource = new ShareResource();
		new Thread(() -> {
			for (int i = 1; i <= 10; i++) {
				shareResource.print5();
			}
		},"AA").start();
		
		new Thread(() -> {
			for (int i = 1; i <= 10; i++) {
				shareResource.print10();
			}
		},"BB").start();
		
		new Thread(() -> {
			for (int i = 1; i <= 10; i++) {
				shareResource.print15();
			}
		},"CC").start();
	}
}

class ShareResource {
	private int number = 1;
	private Lock lock = new ReentrantLock();
	private Condition c1 = lock.newCondition();
	private Condition c2 = lock.newCondition();
	private Condition c3 = lock.newCondition();
	
	public void print5() {
		lock.lock();
		try {
			//1、判断
			while (number != 1) {
				c1.await();
			}
			//2、干活
			for (int i = 1; i <= 5; i++) {
				System.out.println(Thread.currentThread().getName()+"\t "+i);
			}
			//3、唤醒通知
			number = 2;
			c2.signal();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}
	
	public void print10() {
		lock.lock();
		try {
			//1、判断
			while (number != 2) {
				c2.await();
			}
			//2、干活
			for (int i = 1; i <= 10; i++) {
				System.out.println(Thread.currentThread().getName()+"\t "+i);
			}
			//3、唤醒通知
			number = 3;
			c3.signal();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}
	
	public void print15() {
		lock.lock();
		try {
			//1、判断
			while (number != 3) {
				c3.await();
			}
			//2、干活
			for (int i = 1; i <= 15; i++) {
				System.out.println(Thread.currentThread().getName()+"\t "+i);
			}
			//3、唤醒通知
			number = 1;
			c1.signal();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}
}

执行结果:量太大,只截取第一轮和第二轮的部分结果

AA	 1
AA	 2
AA	 3
AA	 4
AA	 5
BB	 1
BB	 2
BB	 3
BB	 4
BB	 5
BB	 6
BB	 7
BB	 8
BB	 9
BB	 10
CC	 1
CC	 2
CC	 3
CC	 4
CC	 5
CC	 6
CC	 7
CC	 8
CC	 9
CC	 10
CC	 11
CC	 12
CC	 13
CC	 14
CC	 15
AA	 1
AA	 2
AA	 3
AA	 4
AA	 5
BB	 1
BB	 2

结果显而易见,程序按着需求在正常运行;

jiguiquan@163.com

文章作者信息...

留下你的评论

*评论支持代码高亮<pre class="prettyprint linenums">代码</pre>

相关推荐