转载。 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分别获取读锁和写锁来提高系统的性能,因为读锁是共享锁,即可以同时有多个线程读取共享资源,而写锁则保证了对共享资源的修改只能是单线程的。

最新文章

  1. git pull 冲突解决
  2. matlab初学之strcat、num2str
  3. jQuery 取值、赋值的基本方法
  4. Javascript中DOM技术的的简单学习
  5. OUYA设备的购买和安装
  6. code::blocks 初使用遇到的问题记录
  7. tar 解压缩命令
  8. DELPHI关闭瑞星监控的源代码
  9. delphi用TAdoStoredProc调用存储过程,兼容sql2005、2008、2014的远程事务问题
  10. PHP语言开发微信公众平台(订阅号)之curl命令
  11. SQLServer数据库中开启CDC导致“事务日志空间被占满,原因为REPLICATION”的原因分析和解决办法
  12. Android - Fragment(二)加载Fragment
  13. iOS 使用矢量图
  14. GG的文化课
  15. .net反编译的九款神器(转载)
  16. centos7设置时间和时区
  17. vector容器的注意事项
  18. utils.js和vue-loader.conf.js
  19. EF DataFirst修改数据类型
  20. [Web 前端] this作用域问题

热门文章

  1. MySQL树
  2. Flask-特殊的装饰器
  3. qt QTableView中嵌入复选框CheckBox 的四种方法总结
  4. nodejs服务端实现post请求
  5. ubuntu下如何关闭某个端口?
  6. jeecg中的datagrid显示一条记录为橙色表示完结
  7. Android数据存储的方式
  8. error: atomic: 没有那个文件或目录
  9. Qt编写自定义控件15-百分比仪表盘
  10. hutool-all 包把实体Bean转化成字符串,以及把字符串转化成Bean对象