Java并发——synchronized和ReentrantLock的联系与区别
来源:互联网 发布:基带工程师知乎 编辑:程序博客网 时间:2024/06/06 20:27
0 前言
本文通过使用synchronized以及Lock分别完成“生产消费场景”,再引出两种锁机制的关系和区别,以及一些关于锁的知识点。
本文原创,转载请注明出处:http://blog.csdn.net/seu_calvin/article/details/52401134
1. synchronized, wait, notify结合实现生产消费场景
1.1 生产者类
/**@author SEU_Calvin*@date 2016/09/01*/public class Producer implements Runnable {@Overridepublic void run() {int count = LockTest.count;while (count <= 3) {synchronized (LockTest.obj) {LockTest.count++;System.out.println("生产者生产产品...现在有"+LockTest.count+"个");if(LockTest.count >= 3){System.out.println("现在产品充足,待消费...");LockTest.obj.notify();//不会立即释放锁,而是等syn代码块执行完再释放锁try {LockTest.obj.wait();//立即释放锁,第三种释放锁是异常导致线程中止} catch (InterruptedException e) {e.printStackTrace();}}}}}}
1.2 消费者类
/**@author SEU_Calvin*@date 2016/09/01*/public class Consumer implements Runnable {@Overridepublic synchronized void run() {int count = LockTest.count;while (count >= 0) {synchronized (LockTest.obj) {LockTest.count--;System.out.println("消费者消费产品...现在有"+LockTest.count+"个");if(LockTest.count <= 0){System.out.println("现在产品缺货,待生产...");LockTest.obj.notify(); // 主动释放对象锁try {LockTest.obj.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}}}
1.3 测试类
public class LockTest {public static final Object obj = new Object();public static int count = 0;public static void main(String[] args) { new Thread(new Producer()).start(); new Thread(new Consumer()).start();}}
1.4 运行结果
这个实例比较简单,主要是通过synchronized,wait, notify结合来实现线程的顺序切换。
2. Lock类
除了wait()、notify()以及synchronized协作完成线程同步之外,使用Lock也可以达到同样的目的。
/**@author SEU_Calvin*@date 2016/09/01*/public class ReentrantLockTest { private volatile int stopFalg = 10;//控制程序执行次数 private volatile int count = 0; private Lock lock = new ReentrantLock(); private ArrayList<Thread> threads = new ArrayList<Thread>(); public static void main(String[] args) throws InterruptedException { final ReentrantLockTest test = new ReentrantLockTest(); new Thread("Producer") { //开启生产者线程 public void run() { test.threads.add(this); while (test.stopFalg > 0) { test.operateResource(this.getName()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }; }.start(); Thread.sleep(1000); //保证生产者线程先启动,继而两者同时生产、消费 new Thread("Consumer") { public void run() { test.threads.add(this); while (test.stopFalg > 0) { test.operateResource(this.getName()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }; }.start(); } public void operateResource(String id) { lock.lock(); //lock开启,锁两个线程都会访问到的同一区域的代码 try { if ("Producer".equals(id)) { if (count < 10) { count++; stopFalg--; System.out.println("Producer=>" + count); } } else if ("Consumer".equals(id)) { if (count > 0) { count--; System.out.println("Consumer=>" + count); } } } finally { lock.unlock();//必须unlock } }}
2.1 运行结果
3. 两者关系与区别汇总
(1)synchronized是JVM层面的实现的,JVM会确保释放锁,而且synchronized使用简单;而Lock是个普通类,需要在代码中finally中显式释放锁lock.unlock(),但是使用灵活。
(2)synchronized采用的是悲观锁机制,线程获得独占锁,而其他线程只能阻塞来等待释放锁。当竞争激烈时CPU频繁的上下文切换会降低效率。而Lock是乐观锁机制,每次假设不存在竞争而不上锁,若存在竞争就重试。当竞争激烈时JVM可以花更少的时间来调度线程,把更多时间用在执行线程上,因此性能最佳。
(3)ReentrantLock可以实现定时锁、轮询锁,可以选择放弃等待或者轮询请求。有效防止了死锁。
lock();//用来获取锁,如果锁已被其他线程获取,则进行等待tryLock(); //尝试获取锁,若成功返回true,失败(即锁已被其他线程获取)则返回falsetryLock(long timeout, TimeUnit unit); //在拿不到锁时会等待一定的时间//两个线程同时通过lock.lockInterruptibly()想获取某个锁时//若线程A获取到了锁,而线程B在等待//线程B调用threadB.interrupt()方法能够中断线程B的等待过程lockInterruptibly();
(4)synchronized是非公平锁。而ReentrantLock可以通过构造函数传入true实现公平锁,即按照申请锁顺序获得锁。
(5)ReentrantLock类有一个重要的函数newCondition(),用于获取Lock上的一个条件,Condition可用于线程间通信。
4. 可重入锁
synchronized以及Lock类锁,两者都是可重入锁。
class MyClass { public synchronized void method1() { method2(); } public synchronized void method2() { }}
可重入锁的意思是,当一个线程执行到某个synchronized方法时,比如说method1,而在method1中会调用另外一个synchronized方法method2,此时线程不必重新去申请锁,而是可以直接执行方法method2。假如synchronized不具备可重入性,此时线程A需要重新申请锁。但是线程A已经持有了该对象的锁,这样线程A会一直等待永远不会获取到的锁。
- Java并发——synchronized和ReentrantLock的联系与区别
- Synchronized 与 ReentrantLock 的区别与联系
- java并发编程: Synchronized与ReentrantLock的区别
- 【Java之并发】ReentrantLock和synchronized区别
- Java 中Synchronized 与 ReentrantLock 区别与联系
- JAVA多线程1——ReentrantLock与synchronized的区别和适用场景
- JAVA的ReentrantLock与synchronized 的区别
- ReentrantLock与synchronized的区别
- ReentrantLock与synchronized的区别
- ReentrantLock与synchronized的区别
- synchronized 与 ReentrantLock 的区别
- Synchronized与ReentrantLock的区别
- ReentrantLock和Synchronized的区别
- ReentrantLock 和synchronized的区别
- synchronized和ReentrantLock的区别
- synchronized和ReentrantLock的区别
- synchronized和ReentrantLock的区别
- synchronized和ReentrantLock的区别
- easyui 3 post ajax
- redmine3.3.0安装问题
- 57. Insert Interval
- xUtils框架
- 纹理映射mipmap
- Java并发——synchronized和ReentrantLock的联系与区别
- 高并发 php uniqid 不重复唯一标识符生成方案
- java编程思想06
- Python基础08 面向对象的基本概念
- YII框架分析笔记1:YII执行流程
- Android使用service+brocastreceive更新UI
- 关于 Scroller的
- 腾讯2016研发工程师笔试题(一)笔记
- 深度学习算法实践14---去噪自动编码机(dA)的Theano实现