Java线程锁(一)
在Linux系统下,启动一个新的进程必须要给它分配独立的地址空间,建立众多的数据表来维护它的代码段,堆栈段和数据段,这是一种昂贵的多任务工作方式。而在进程中同时运行多个线程,多个线程彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于一个进程所花费的空间,而且线程之间彼此切换所需要的时间远远小于进程之间切换所需要的时间
多线程并发面临的挑战:
- 多线程资源共享
- 线程死锁
- 锁的选择
由于多个线程是共同占用所属进程的资源和地址空间的,如果多个线程要同时访问某个资源怎么办?
其实在Java并发编程中,经常遇到多个线程访问同一个 共享资源,这时候作为开发者必须考虑如何维护数据一致性,这就是Java锁机制(同步问题)的来源
Java提供了多种多线程锁机制的实现方式,常见的有:
- Synchronized
- ReentrantLock
- Semaphore
- Atomiclnteger等
每种机制都有优缺点与各自的适用场景
Synchronized(依赖于JVM,可靠性高,性能随Java版本升级而提高)
在Java中Synchronized关键字被常用于维护数据一致性
Synchronized机制是给共享资源上锁,只有拿到锁的线程才可以访问共享资源,这样就可以强制使得对共享资源的访问都是按顺序的
Synchronized来实现多线程的同步操作是很简单的,在需要同步的对方的代码块,类,方法中加入此关键字,它能保证在同一个时刻最多只有一个线程执行同一个对象的同步代码,可保证修饰的代码在执行过程中不会被其他线程干扰。
当线程使用Synchronized等待锁时 是不能被Thread.interrupt () 中断的,否则会造成线程死锁
Synchronized修饰的代码具有原子性和可见性,在需要进程同步的程序中使用的频率非常高,可满足一般的进程同步要求
ReentrantLock(可重入锁)
ReentrantLock(可重入锁)可以被线程多次重复进行获取操作
ReentrantLock继承接口Lock并实现了接口中定义的方法,除了能完成Synchronized所能完成的所有工作,还提供了可响应中断锁,可轮询锁请求,定时锁等 避免多线程死锁的方法
Lock依赖于特殊的CPU,可以认为不受JVM的约束,可以通过其他语言平台来完成底层的实现
Synchronized与ReentrantLock的性能比
在并发量较小的多线程应用程序中,ReentrantLock与Synchronized性能相差无几
在高并发量的情况下,Synchronized性能迅速下降几十倍,而ReetrantLock的性能仍然维持一个水准
建议:在高并发量的情况下使用ReentrantLock
ReentrantLock引入了两个概念: 公平锁与非公平锁
公平锁指的是锁的分配机制是公平的,通常 先对锁提出获取请求的线程 会先被分配到锁。
非公平锁指的是JVM按随机,就近原则分配锁的机制被称为非公平锁
ReentrantLock在构造函数中提供了是否公平锁的初始化,默认是非公平锁
非公平锁实际执行的效率远超公平锁,除非程序有特殊要求,否则常用非公平锁的分配机制
ReentrantLock通过 lock () 与 unlock () 来进行加锁与解锁操作,与Synchronized会被JVM自动解锁机制不同,ReentrantLock加锁后需要手动进行解锁
为了避免程序出现异常而无法正常解锁的情况,使用ReentrantLock必须在finally控制块中进行解锁操作
使用方式的示例代码如下:
Lock lock=new ReentrantLock();try{lock.lock();}catch(){}finally{lock.unlock();}
Semaphore
由于Synchronized和ReentrantLock是互斥锁,互斥是进程同步关系的一种特殊情况,相当于只存在一个临界资源,因此最多只能给一个线程提供服务。在实际复杂的多线程应用程序中可能存在多个临界资源,这时可以借助Semaphore信号量来完成多个临界资源的访问
Semaphore基本能完成ReentrantLock的所有工作,使用方法类似,通过acquire () 与 release () 方法来获取和释放临界资源
Semaphore.accquire () 方法默认为可响应中断锁,与ReentrantLock.lockInterruptibly () 作用效果一致,也就是说在等待临界资源的过程中可以被Thread.interrupt () 方法中断
Semaphore也实现了 可轮询的锁请求 与 定时锁 的功能,除了方法名accquire与lock不同,使用方法与ReentrantLock几乎一致。Semaphore也提供了公平锁与非公平锁机制,也可以在构造函数中进行初始化设定
Semaphore的锁释放操作也由手动进行,与ReentrantLock一样,为避免线程因抛出异常而无法正常释放锁的情况发生,释放锁的操作也必须在finally代码块中完成
AtomicInteger
AtomicInterger是一系列相同类的代表之一,常见的还有AtomicLong等,它们的实现原理都相同,区别就在于运算对象类型的不同
在多线程应用程序中,如++i ,i++等运算不具有原子性,是不安全的线程操作之一
通常使用Synchronized将该操作变成一个原子操作,但JVM为此类操作特意提供了一些同步类,从而使得更加方便,并且程序运行效率变得更高,
AtomicInteger的性能是ReentrantLock的好几倍
Java线程锁总结:
Synchronized:
在资源竞争不是很激烈的情况下,偶尔有同步的情况下,Synchronized是很合适的,因为编译程序通常会尽可能的优化Synchronized,可读性也很好
ReentrantLock:
在资源竞争不激烈的情况下,性能稍微比Synchronized差一点,但是当同步很激烈情况下,Synchronized的性能一下子能下降好几十倍,而ReentrantLock依然能维持常态
在高并发量的情况下使用ReentrantLock
Atomic:
在资源竞争不激烈的情况下,性能比Synchronized差一点,而资源竞争激烈的情况下,也能维持常态
在资源竞争激烈的情况下,Atomic的性能会优于ReentrantLock一倍左右
缺点在于,只能同步一个值,一段代码中只能出现一个Atomic的变量,多余一个同步无效,它不能在多个Atomic之间同步
个人建议:
写同步的时候,优先考虑Synchronized,如果有特殊的情况,再进一步优化
ReentrantLock和Atomic如果用的不好,不仅不能提高性能,还可能带来灾难
Java线程锁(一)相关推荐
- java lock 效率_工作常用4种Java线程锁的特点,性能比较、使用场景
多线程的缘由 在出现了进程之后,操作系统的性能得到了大大的提升.虽然进程的出现解决了操作系统的并发问题,但是人们仍然不满足,人们逐渐对实时性有了要求. 使用多线程的理由之一是和进程相比,它是一种非常花 ...
- Java多线程系列(四):4种常用Java线程锁的特点,性能比较、使用场景
多线程的缘由 在出现了进程之后,操作系统的性能得到了大大的提升.虽然进程的出现解决了操作系统的并发问题,但是人们仍然不满足,人们逐渐对实时性有了要求. 使用多线程的理由之一是和进程相比,它是一种非常花 ...
- java 线程锁概念_Java多线程——锁概念与锁优化
为了性能与使用的场景,Java实现锁的方式有非常多.而关于锁主要的实现包含synchronized关键字.AQS框架下的锁,其中的实现都离不开以下的策略. 悲观锁与乐观锁 乐观锁.乐观的想法,认为并发 ...
- java线程 锁_Java多线程(二) 多线程的锁机制
当两条线程同时访问一个类的时候,可能会带来一些问题.并发线程重入可能会带来内存泄漏.程序不可控等等.不管是线程间的通讯还是线程共享数据都需要使用Java的锁机制控制并发代码产生的问题.本篇总结主要著名 ...
- Java——线程锁,死锁,等待唤醒机制
一.线程锁 线程安全问题 其实,线程安全问题都是由全局变量及静态变量引起的.若每个线程中对全局变量.静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的:若有多个线程同时执行写操作,一般 ...
- java线程锁标记_java 线程 中断标志位
课程素材来自 http://enjoy.ke.qq.com/ 版权所有 java线程中,线程中断方法详解: 线程自然终止:自然执行完或抛出未处理异常 stop(),resume(),suspen ...
- java线程锁机制_多线程之锁机制
前言 在Java并发编程实战,会经常遇到多个线程访问同一个资源的情况,这个时候就需要维护数据的一致性,否则会出现各种数据错误,其中一种同步方式就是利用Synchronized关键字执行锁机制,锁机制是 ...
- java 线程锁Lock
文章目录 说明 分享 资料 synchronized与Lock对比 Lock Lock 接口方法 实现类 ReentrantLock ReadWriteLock ReadWriteLock 接口方法 ...
- java线程锁为什么要唯一,java线程同步-锁 - 谁说这么长又没有中心思想还与个人技术主题无关的的标题是胡闹??? - OSCHINA - 中文开源技术交流社区...
1.synchronized 用在方法和代码块上有什么区别呢? synchronized 用在方法签名上(以test为例),当某个线程调用此方法时,会获取该实例的对象锁,方法未结束之前,其他线程只能去 ...
最新文章
- 用CMake构建工程时 cmake -G“Unix Makefiles“ 的使用
- 解决 json_encode 中文乱码
- 60%的安卓APP存在漏洞,平均每个有39个漏洞
- ubuntu16.04 xfce4的鼠标主题设置为oxygen-red、修改文件夹背景颜色、两处系统字体设置、右键菜单添加压缩解压选项
- Spark读取HDFS上的Snappy压缩文件所导致的内存溢出问题 java.lang.OutOfMemoryError: GC overhead limit exceeded
- c语言每轮for循环初始化i,十三.Linux博客-2016年8月18日while、for特殊用法、selet循环与菜单、函数...
- mybatis 依赖于jdbc_大数据基础:Mybatis零基础入门
- mysql java文件导入导出_MySQL文件导出和导入
- 学习记录-程序语言基础(1)
- .net Core 部署到 Linux
- row_number()分页返回结果顺序不确定
- ActionBarSherlock SlidingMenu整合,解决SlidingMenu example的getSupportActionBar()方法不能用问题...
- JAVA学习-类与对象(韩顺平java-高级篇)
- 单元测试用例编写总结
- 黑鹰安全网_育鹰计划_笔记
- DevOps成功的5个关键
- App Store风靡!当下热门应用商店简析
- 指定locale为en US
- 计算机桌面有什么,电脑桌面是什么
- python的iloc与loc函数