Java并发——synchronized和ReentrantLock的联系与区别
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 {
@Override
public 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();// 主动释放对象锁
try {
LockTest.obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
}
}
}
1.2 消费者类
/*
*@author SEU_Calvin
*@date 2016/09/01
*/
public class Consumer implements Runnable {
@Override
public 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. 两者关系与区别汇总
从上面两个实例的实现可以引出Synchronized和Lock的关系:
(1)ReentrantLock与synchronized有相同的并发性和内存语义。但是ReentrantLock还包含了区别于synchronized的以下特性。
(2)等待可中断:在持有锁的线程长时间不释放锁的时候,等待的线程可以选择放弃等待。有效防止了死锁。
lock();//用来获取锁,如果锁已被其他线程获取,则进行等待
tryLock(); //尝试获取锁,若成功返回true,失败(即锁已被其他线程获取)则返回false
tryLock(long timeout, TimeUnit unit); //在拿不到锁时会等待一定的时间
//两个线程同时通过lock.lockInterruptibly()想获取某个锁时
//若线程A获取到了锁,而线程B在等待
//线程B调用threadB.interrupt()方法能够中断线程B的等待过程
lockInterruptibly();
(3)公平锁:按照申请锁的顺序来获得锁。synchronized是非公平锁。ReentrantLock可以通过构造函数实现公平锁。
new RenentrantLock(boolean fair);
(4)绑定多个Condition,添加多个检控条件:通过多次new Condition可以获得多个Condition对象。
(5)ReentrantLock可以获取各种锁的信息,比如可以查看锁的状态,锁是否被锁上了。可以查看当前有多少线程在等待锁。
(6)Lock使用更灵活、性能更佳。性能的优化体现在,当许多线程都想访问共享资源时,JVM可以花更少的时间来调度线程,把更多时间用在执行线程上。
(7)由于synchronized是在JVM层面实现的,因此系统可以监控锁的释放与否,而ReentrantLock使用代码实现的,系统无法自动释放锁,需要在代码中finally子句中显式释放锁lock.unlock()。同时由于ReentrantLock是类,使用时需要import相关类。
(8)总结:在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态。
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的联系与区别的更多相关文章
- java并发编程——通过ReentrantLock,Condition实现银行存取款
java.util.concurrent.locks包为锁和等待条件提供一个框架的接口和类,它不同于内置同步和监视器.该框架允许更灵活地使用锁和条件,但以更难用的语法为代价. Lock 接口 ...
- java 并发——synchronized
java 并发--synchronized 介绍 在平常我们开发的过程中可能会遇到线程安全性的问题,为了保证线程之间操作数据的正确性,我们第一想到的可能就是使用 synchronized 并且 syn ...
- Java并发系列[5]----ReentrantLock源码分析
在Java5.0之前,协调对共享对象的访问可以使用的机制只有synchronized和volatile.我们知道synchronized关键字实现了内置锁,而volatile关键字保证了多线程的内存可 ...
- Java并发——synchronized关键字
前言: 只要涉及到Java并发那么我们就会考虑线程安全,实际上能够实现线程安全的方法很多,今天先介绍一下synchronized关键字,主要从使用,原理介绍 一.synchronized的使用方法 1 ...
- Java并发-Synchronized关键字
一.多线程下的i++操作的并发问题 package passtra; public class SynchronizedDemo implements Runnable{ private static ...
- Java锁Synchronized对象锁和类锁区别
java的内置锁:每个java对象都可以用做一个实现同步的锁,这些锁成为内置锁.线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁.获得内置锁的唯一途径就是进入这个锁的保 ...
- Java并发编程基础-ReentrantLock的机制
同步锁: 我们知道,锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁能够防止多个线程同时访问共享资源,在Lock接口出现之前,Java应用程序只能依靠synchronized关键字来实现同步锁 ...
- [Java] [Lock] [Synchronized VS ReentrantLock]
Overview java编写多线程程序时,为了保证线程安全,需要对数据进行同步,经常用到的两种同步方式就是synchronized和重入锁ReentrantLock. 相似点 都是加锁方式 都是阻塞 ...
- java并发编程基础-ReentrantLock及LinkedBlockingQueue源码分析
ReentrantLock是一个较为常用的锁对象.在上次分析的uil开源项目中也多次被用到,下面谈谈其概念和基本使用. 概念 一个可重入的互斥锁定 Lock,它具有与使用 synchronized 相 ...
随机推荐
- (转载)ASP.NET Quiz Answers: Does Page.Cache leak memory?
原文地址:http://blogs.msdn.com/b/tess/archive/2006/08/11/695268.aspx "We use Page.Cache to store te ...
- mybatis批量插入插入数据、批量条件查询
ps:参考文章连接:https://www.cnblogs.com/admol/articles/4248159.html 关于个人的使用经验:先把数据放到bean中,多个的话就全放入list集合,如 ...
- Spring cloud Eureka 服务治理(搭建服务注册中心)
服务之类是微服务架构中最为核心的基础模块,它主要用来实现各个微服务实例的自动化注册和发现. 1. 服务注册 在服务治理框架中,通常会构建一个注册中心,每个服务单元向注册中心登记自己提供的服务,将主机. ...
- Mysql数据库学习总结(一)
数据库概念 数据库(Database)是按照数据结构来组织.存储和管理数据,建立在计算机存储设备上的仓库. 简单说,数据库就是存放数据的仓库.和图书馆存放书籍.粮仓存放粮食类似. 数据库分类 分为 关 ...
- UVA 11990 ``Dynamic'' Inversion (线段树套BIT,分治)
题目要求可转化为查询一个区间内有多少数比val大(或者小). 区间用线段树分解(logN),每个区间维护一rank树. rank可用BIT查询,往BIT里面插值,为了保证不同区间的BIT互不影响要先离 ...
- POJ2112 Optimal Milking---二分+Floyd+网络流
题目链接: https://vjudge.net/problem/POJ-2112 题目大意: k个机器,每个机器最多服务m头牛. c头牛,每个牛需要1台机器来服务. 告诉你牛与机器每个之间的直接距离 ...
- NFS服务器实现文件共享
NFS服务器运行原理 实战配置NFS服务器 配置Samba服务器及实现文件共享 (一)NFS器服务端描述 NFS服务器: Network File System,网络文件系统使FreeBSD支持的一种 ...
- 初学AC自动机
前言 一直听说\(AC\)自动机是一个很难很难的算法,而且它不在\(NOIP\)提高组范围内(这才是关键),所以我一直没去学. 最近被一些字符串题坑得太惨,于是下定决心去学\(AC\)自动机. 简介 ...
- 索引属性 name指定
创建索引时的格式: db.collection.ensureIndex({param},{param}) 其中,第一个是索引的值,之前一直只用到了第一个,第二个参数便是索引的属性 比较重要的属性有: ...
- C语言 数组名不是首地址指针
今天上计算机系统课的时候老师讲到了C中的聚合类型的数据结构.在解释数组名的时候说"数组名是一个指针,指向该数组的第一个元素",附上ppt(第二行): 我觉得这是不正确的,是一个常见 ...