转载。 https://blog.csdn.net/wu1226419614/article/details/73740899

我们在面试的时候,时常被问到如何保证线程同步已经对共享资源的多线程编程。我们当然用同步代码块,同步方法,又或者是用java提供的锁机制来达到对共享资源变量的同步控制。

那么我们什么时候用synchronized,什么时候用lock,以及他们的区别是什么呢;

首先来说synchronized 是Java的关键字,是Java的内置特性,在JVM层面实现了对临界资源的同步互斥访问,通过对对象的头文件来操作,从而达到加锁和释放锁的目的。对象的头文件如下图:

那么synchronized的缺点是啥呢:

1)不能响应中断;

2)同一时刻不管是读还是写都只能有一个线程对共享资源操作,其他线程只能等待

3)锁的释放由虚拟机来完成,不用人工干预,不过此即使缺点也是优点,优点是不用担心会造成死锁,缺点是由可能获取到锁的线程阻塞之后其他线程会一直等待,性能不高。

而lock接口的提出就是为了完善synchronized的不完美的,首先lock是基于jdk层面实现的接口,和虚拟机层面不是一个概念;其次对于lock对象中的多个方法的调用,可以灵活控制对共享资源变量的操作,不管是读操作还是写操作;

lock接口的关系图:

ReentrentLock对象和ReentrentReadWriteLock为我们日常开发中见到和用到比较多的两个类;他们都是可重入的锁,即当同一线程获取到锁之后,他在不释放锁的情况下,可以再次获取到当前已经拿到的锁,只需标记获取到锁的次数加一即可;

下面已ReentrentLock的使用为例,来说明如何对共享变量的控制;要求线程甲和线程乙各自轮询添加数字到list集合中;假设说次数为3次;

package part6.jstack;

import java.util.ArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* Created by xq on 17/6/26.
*/
public class TestLock {
private ArrayList<String> arrayList = new ArrayList<>();
Lock lock = new ReentrantLock();
public static void main(String[] args) {
final TestLock test = new TestLock();
for (int i = 0; i < 3; i++) { final Integer count=i;
new Thread("甲"){public void run() {
test.insert(Thread.currentThread(),count);
};}.start();
new Thread("乙"){public void run() {
test.insert(Thread.currentThread(),count);
};}.start(); }
test.arrayList.stream().forEach(e->{
System.out.println(e);
});
} public void insert(Thread thread,Integer count) { lock.lock();
try {
//线程获取到了锁
for (int i = 0; i<5; i++) {
arrayList.add("第"+count+"次"+"线程"+thread.getName()+i);
}
} catch (Exception e) { }finally {
//线程释放锁
lock.unlock();
}
}
}
执行结果如下图:

从结果中可以看出,在一个时刻只能有一个线程获取到锁并执行打印;
那么lock和synchronized的区别对比如下:
1)synchronized 在成功完成功能或者抛出异常时,虚拟机会自动释放线程占有的锁;而Lock对象在发生异常时,如果没有主动调用unLock()方法去释放锁,则锁对象会一直持有,因此使用Lock时需要在finally块中释放锁;
2)lock接口锁可以通过多种方法来尝试获取锁包括立即返回是否成功的tryLock(),以及一直尝试获取的lock()方法和尝试等待指定时间长度获取的方法,相对灵活了许多比synchronized;
3) 通过在读多,写少的高并发情况下,我们用ReentrantReadWriteLock分别获取读锁和写锁来提高系统的性能,因为读锁是共享锁,即可以同时有多个线程读取共享资源,而写锁则保证了对共享资源的修改只能是单线程的。

线程的同步控制synchronized和lock的对比和区别的更多相关文章

  1. 第41天学习打卡(死锁 Lock synchronized与Lock的对比 线程协作 使用线程池)

    死锁 多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行,而导致两个或者多个线程都在等待对方释放资源,都停止执行的情形.某一个同步块同时拥有"两个以上对象的锁"时 ...

  2. Java多线程之线程同步【synchronized、Lock、volatitle】

    线程同步 线程同步:当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,而其他线程又处于等待状态,实现线程同步的方法有很多. ...

  3. 5分钟搞清楚Synchronized和Lock的概念与区别

    前言 并发编程中,锁是经常需要用到的,今天我们一起来看下Java中的锁机制:synchronized和lock. Synchronized 和 Lock的概念 Synchronized 是Java 并 ...

  4. synchronized与Lock、volatile的区别

    synchronized与volatile的区别 volatile是线程同步的轻量级实现,因此volatile性能好于synchronized voaltile修饰变量,synchronized修饰方 ...

  5. Java多线程编程(四)—浅谈synchronized与lock

    一.共享资源竞争问题 在Java语言的并发编程中,由于我们不知道线程实际上在何时运行,所以在实际多线程编程中,如果两个线程访问相同的资源,那么由于线程运行的不确定性便会在这种多线程中产生访问错误.所以 ...

  6. 线程安全、数据同步之 synchronized 与 Lock

    本文Demo下载传送门 写在前面 本篇文章讲的东西都是Android开源网络框架NoHttp的核心点,当然线程.多线程.数据安全这是Java中就有的,为了运行快我们用一个Java项目来讲解. 为什么要 ...

  7. 简单的线程同步问题:两个线程交替执行N次【Synchronized、Lock、ArrayBlockingQueue】

    方法一:传统的线程方法import org.apache.log4j.Logger; /** * 两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象.<br/> * ...

  8. 【Java线程】锁机制:synchronized、Lock、Condition

    http://www.infoq.com/cn/articles/java-memory-model-5  深入理解Java内存模型(五)——锁 http://www.ibm.com/develope ...

  9. Java 线程锁机制 -Synchronized Lock 互斥锁 读写锁

    (1)synchronized 是互斥锁: (2)ReentrantLock 顾名思义 :可重入锁 (3)ReadWriteLock :读写锁 读写锁特点: a)多个读者可以同时进行读b)写者必须互斥 ...

随机推荐

  1. 图像傅里叶变换(快速傅里叶变换FFT)

    学习DIP第7天,图像傅里叶变换 转载请标明出处:http://blog.csdn.net/tonyshengtan,欢迎大家转载,发现博客被某些论坛转载后,图像无法正常显示,无法正常表达本人观点,对 ...

  2. art-template自定义函数

    自定义函数 // 百分比计算 template.defaults.imports.percentage = function (num1, num2) { var res; if(!num1 & ...

  3. 【洛谷4001】 [ICPC-Beijing 2006]狼抓兔子(最小割)

    传送门 洛谷 Solution 直接跑最小割板子就好了. 代码实现 #include<stdio.h> #include<stdlib.h> #include<strin ...

  4. java将PDF的前几页拆出来组成新pdf

    /** * 截取pdfFile的第from页至第end页,组成一个新的文件名 * @param pdfFile 需要分割的PDF * @param savepath 新PDF * @param fro ...

  5. Java多线程之ThreadPoolExecutor详解使用

    1.概述 我将讲解JAVA原生线程池的基本使用,并由此延伸出JAVA中和线程管理相关的类结构体系,然后我们详细描述JAVA原生线程池的结构和工作方式 2.为什么要使用线程池 前文我们已经讲到,线程是一 ...

  6. java TimeUnit 的使用

    主要作用 时间颗粒度转换 延时 1.时间颗粒度转换 public long toMillis(long d) //转化成毫秒 public long toSeconds(long d) //转化成秒 ...

  7. CISCO实验记录三:CDP邻居发现

    一.CDP邻居发现要求 1.识别二层连接 2.识别CDP邻居 二.CDP邻居发现操作 1.CDP邻居发现 #interface gigabitEthernet 0/0/0 //启动端口 #no shu ...

  8. python排序之冒泡排序

    def sort(list): for i in range(len(list)): for j in range(len(list) - i - 1): if list[j] < list[j ...

  9. 尚硅谷周阳老师-redis脑图课件

    因为脑图原件是.mmap格式,使用wps和xmind打开都会有格式不兼容的问题,这里我们可以使用mindmanager存为html5交互式格式, 提供在线阅读.因为阿里云学生服务器带宽有限,这里打开加 ...

  10. antd源码分析之——标签页(tabs 1.组件结构)

    由于ant Tabs组件结构较复杂,共分三部分叙述,本文为目录中第一部分(高亮) 目录 一.组件结构 antd代码结构 rc-ant代码结构 1.组件树状结构 2.Context使用说明 3.rc-t ...