Java并发机制(2)--synchronized与Lock
本内容整理自:博客园-海 子-java并发编程系列-http://www.cnblogs.com/dolphin0520/category/602384.html
1、基础:
1、什么时候出现线程安全问题?
在多线程编程中,可能会出现多个线程同时访问一个资源(共享资源)的情况,由于每个线程的过程不可控,导致程序实际运行结果与愿望相违背。
2、如何解决线程安全问题?
一般而言,所有的并发模式都采用“序列化访问临界资源”的方案:即在同一时刻,只允许一个线程访问临界资源。
上述方式也称为:同步互斥访问:在访问临界资源的代码前加一个所,访问完以后释放锁。java中有两种方式实现互斥同步:synchronized和Lock;
3、线程创建的两种方式:来自 博客园-海 子-http://www.cnblogs.com/dolphin0520/p/3913517.html
2、synchronized实现方式
1、synchronized加锁的三种方式及对应原理:
(1):synchronized修饰普通方法,锁范围是实例范围:所有的对象都自动含有单一的锁(监视器monitor),调用对象中的synchronized方法时,该对象会被加锁,该对象内的其他加锁方法不能被其他线程访问。如: Person(){synchronized eat(){} synchronized run()};当线程thread1调用该对象的eat时,thread2不能调用run方法;
底层原理:如:以常量池中ACC_SYNCHRONIZED标示符,为访问标识,方法调用时,先检查该访问标志是否被设置,若是,则线程先获取monitor,方法执行完释放monitor。
public synchronized void method(){
System.out.println("Hello Word") ;
}
(2):synchronized修饰static方法,锁范围是类范围:所有的Person类对象都会被锁住。线程1和线程2的eat1方法只能被一个调用。而eat2方法是实例同步的,线程1锁住对象1,线程2锁住对象2,eat2可以被线程1和线程2同步调用。
public class Person implements Runnable{
static int apple=0;
//锁住当前的Class类对象,即Person类。
public static synchronized void eat1(){
i++;//非原子性操作;
}
//锁住当前实例,即只对Person的一个实例对象加锁;
public synchronized void eat2(){
i++;
}
}
(3): synchronized修饰同步代码块,所范围是实例对象:有时对整个方法进行加锁,显得不必要,同时也会降低执行效率,需要的仅仅是对方法中某几步操作进行加锁。
public class Person{ |
![]() |
注:一个线程可以获取多次该对象的锁:如对象o1调用eat方法,而eat又调用了该对象的run方法,jvm会自动递增加锁的次数,每次离开一个synchronized方法,计数减一,一直到0。
注:synchronized的优化等内容见以后整理(待补充。。。)。
3、Local的实现方式(java.util.concurrent.locks包下Local接口)
1、有了synchronized为什么还要使用Local?
(1)synchronized的缺陷:synchronized只有两种执行结果[1]执行完释放锁。[2]异常,jvm释放锁。但是当一个持有锁的线程被阻塞(如IO),那么其他线程也只能等。再比如,多线程同时读取文件时,不会造成冲突,但是为了避免读写冲突,读操作也被synchronized,效率很低。
(2)使用Local能解决上述问题,而且,Local是java中的一个类(接口),实现多种方法来获取处理锁;synchronized是java语言内置关键字,无别功能。
2、Local的使用方式:
(1):获取锁的方式:
Lock中有四种获取锁的方法: (1):lock():获取锁,若锁被其他线程获取,等待。常用try&catch包围,用完后需要主动释放,unlock();
(2):tryLock():尝试获取锁,锁为空闲状态才获取该锁,若成功返回true;失败返回false;
(3):tryLock(long time, TimeUnit unit):尝试获取锁,并在等待时间内尝试获取,,获取到返回true;
(4):lockInterruptibly():使用该方法获取锁,若正在等待获取,改线程可以相应interrupt()方法,结束等待。
(2):方法内声明并lock与方法外声明,方法内lock:
public class Test { Thread-0得到了锁 |
public class Test { Thread-0得到了锁 |
3、ReentrantLock:是接口Lock的唯一直接实现类,一般使用 Lock lock = new ReentrantLock(); 来获取一个锁对象。
4、锁的几种类型
1、可重入锁:thread1执行锁方法method1,metho1调用锁方法method2时不必重新获取锁(同一对象);synchronized与reentrantLock都是可重入锁,
2、可中断锁:synchronized不可中断,Lock是可以中断的(如lockInterruptibly())
3、公平锁:尽量以请求锁的顺序来获取锁。synchronized不公平锁,ReentrantLock默认不公平,可以设为公平。
4、读写锁:读写锁将对一个资源(比如文件)的访问分成了2个锁,一个读锁和一个写锁。ReadWriteLock就是读写锁,它是一个接口,ReentrantReadWriteLock实现了这个接口。可以通过readLock()获取读锁,通过writeLock()获取写锁。
具体事例参见大神ref:博客园-海 子-http://www.cnblogs.com/dolphin0520/p/3923167.html
5、Lock和synchronized的比较
(1):Lock是一个接口,主要实现类有:ReentrantLock(直接实现类)和ReentrantReadWriteLock。synchronized是Java中的关键字,是内置的语言实现。
(2):synchronized异常时会自动释放锁,Lock必须主动释放(必须放在finally{*.unlock()});
(3):Lock可以实现让等待锁的线程相应中断(interrupt);synchronized不可以。
(4):Lock可以获知有没有获取到锁。
(5):Lock可以提高多个线程进行『读』操作的效率。资源竞争不激烈,两者差不多;资源竞争激烈,Lock性能远好于synchronized。
更详细请移步:博客园-海 子-java并发编程系列-http://www.cnblogs.com/dolphin0520/category/602384.html
Java并发机制(2)--synchronized与Lock的更多相关文章
- Java并发编程:synchronized、Lock、ReentrantLock以及ReadWriteLock的那些事儿
目录 前言 synchronized用法 修饰方法 修饰实例方法 修饰静态方法 同步代码块 引出Lock Lock用法 子类:ReentrantLock 读写分离锁:ReadWriteLock Loc ...
- Java并发编程:synchronized和Lock
转自 : http://www.tuicool.com/articles/qYFzUjf
- Java并发编程:synchronized
Java并发编程:synchronized 虽然多线程编程极大地提高了效率,但是也会带来一定的隐患.比如说两个线程同时往一个数据库表中插入不重复的数据,就可能会导致数据库中插入了相同的数据.今天我们就 ...
- 《Java并发编程的艺术》Java并发机制的底层实现原理(二)
Java并发机制的底层实现原理 1.volatile volatile相当于轻量级的synchronized,在并发编程中保证数据的可见性,使用 valotile 修饰的变量,其内存模型会增加一个 L ...
- 4、Java并发编程:synchronized
Java并发编程:synchronized 虽然多线程编程极大地提高了效率,但是也会带来一定的隐患.比如说两个线程同时往一个数据库表中插入不重复的数据,就可能会导致数据库中插入了相同的数据.今天我们就 ...
- 【java并发编程艺术学习】(三)第二章 java并发机制的底层实现原理 学习记录(一) volatile
章节介绍 这一章节主要学习java并发机制的底层实现原理.主要学习volatile.synchronized和原子操作的实现原理.Java中的大部分容器和框架都依赖于此. Java代码 ==经过编译= ...
- Java 并发系列之二:java 并发机制的底层实现原理
1. 处理器实现原子操作 2. volatile /** 补充: 主要作用:内存可见性,是变量在多个线程中可见,修饰变量,解决一写多读的问题. 轻量级的synchronized,不会造成阻塞.性能比s ...
- Java并发机制的底层实现原理之volatile应用,初学者误看!
volatile的介绍: Java代码在编译后会变成Java字节码,字节码被类加载器加载到JVM里,JVM执行字节码,最终需要转化为汇编指令在CPU上执行,Java中所使用的并发机制依赖于JVM的实现 ...
- Java 并发机制底层实现 —— volatile 原理、synchronize 锁优化机制
本书部分摘自<Java 并发编程的艺术> 概述 相信大家都很熟悉如何使用 Java 编写处理并发的代码,也知道 Java 代码在编译后变成 Class 字节码,字节码被类加载器加载到 JV ...
- 《Java并发编程的艺术》读书笔记:二、Java并发机制的底层实现原理
二.Java并发机制底层实现原理 这里是我的<Java并发编程的艺术>读书笔记的第二篇,对前文有兴趣的朋友可以去这里看第一篇:一.并发编程的目的与挑战 有兴趣讨论的朋友可以给我留言! 1. ...
随机推荐
- pytest--pytest基本介绍
pytest简介 pytest 是 python 的第三方单元测试框架,比自带的 unittest 更简洁和高 效,同时兼容 unittest 框架.它还有如下优点: 1.简单灵活,容易上手,文档丰富 ...
- 部署Nginx网站服务
编译安装Nginx nginx 官方 : http://nginx.org/ yum -y install pcre-devel zlib-devel ##安装相关依赖包 ./configure ...
- 神奇!这款 Vue 后台框架居然不用手动配置路由
前言 做 Vue 开发脱离不了路由,尤其是中大型项目,页面多且杂,在配置路由的时候总是会变得逐渐暴躁,因为费时,并且又没有什么太多技术含量,总觉得是在浪费时间. 另外如果接手了别人的项目,当业务有变更 ...
- 赶紧收藏!最好用的BI工具都在这了!
1.bi厂商--思迈特软件Smartbi 广州思迈特软件有限公司成立于2011 年,以提升和挖掘企业客户的数据价值为使命,专注于商业智能与大数据分析软件产品与服务.思迈特软件是国家认定的"高 ...
- C# 复杂类实例的相等判断
在比较两个对象是否完全相同时,对于string, int等其他value object,可以直接通过"=="或者"Equals"来进行判断.但是对于复杂类,如下 ...
- shell脚本练习案例
转至:https://www.cnblogs.com/tui463/archive/2004/01/13/12663024.html shell脚本练习案例 案例一:通过位置变量创建系统账户及密码 分 ...
- Word:在文中插入对参考文献的引用
1.工具栏→插入→交叉引用 2."交叉引用"工具栏 引用类型:编号项: 引用内容:段落编号 选中要引用的参考文献编号 3.结果
- C# Md5Hash
/// <summary> /// MD5 32位加密(大写) /// </summary> /// <param name="str">< ...
- Linux CentOS7.X-目录操作命令
一.安装vim 由于安装Centos7MINI版本里面没有vim命令,只有vi命令,所以安装vim命令,默认系统只带了vim-minimal.x86_64包,需要安装其他的3个包才能用vim命令 1. ...
- Docker - 安装&测试
一.什么是Docker Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源. Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中 ...