Java锁概念基础
Java中的锁不管是Lock还是synchronized都可以分为互斥锁和非互斥锁。
互斥锁只能被一个线程持有,其他线程只能等待锁的释放。synchronized,ReentrantLock,ReadWriteReentrantLock的WriteLock是互斥的,但ReadLock不是互斥的。
FileLock可以设置为互斥锁或者非互斥锁。
实现锁时可以基于操作系统的调度,也可以以自旋的形式来实现。
利用操作系统的指令,让线程等待,当锁可用时,让线程醒过来。这种适合需要等待长时间的。如果等待的时间短,这个操作的代价是较大的。
用循环不断的轮询锁的状态,锁可用的时候就退出。这就是自旋锁。这样里面基本不做什么事情的循环是非常耗CPU的,如果等待锁的时间很长,用这种方式是不合适的。
自旋锁是JVM实现的,下面的例子可以简单的描述自旋锁
public class MyWaitNotify3{ MonitorObject myMonitorObject = new MonitorObject();
boolean wasSignalled = false; public void doWait(){
synchronized(myMonitorObject){
while(!wasSignalled){
try{
} catch(InterruptedException e){...}
}
//clear signal and continue running.
...
wasSignalled = false;
}
} public void doNotify(){
synchronized(myMonitorObject){
wasSignalled = true;
myMonitorObject.notify();
}
}
}
没有其他的线程调用doNotify之前,doWait将一直自旋,等待wasSignalled变为true。
自旋锁的缺点:
1.自旋锁一直占用CPU,他在未获得锁的情况下,一直运行自旋,所以占用着CPU,如果不能在很短的时 间内获得锁,这无疑会使CPU效率降低。
2.在用自旋锁时有可能造成死锁,当递归调用时有可能造成死锁。
可以使用-XX:+UseSpinning来打开自旋锁,使用-XX:PreBlockSpin来设置等自旋待的次数。
有些时候我们会在完全没必要的情况下用到了锁,可以使用逃逸分析和锁消除来提升系统的性能。
例如,下面的局部变量StringBuffer完全用不到加锁,反而会影响性能。
public String createNewString(String a,String b){
StringBuffer sb = new StringBuffer();
return sb.append(a).append(b);
}
逃逸分析和锁消除可以使用-XX:+DoEscapeAnalysis和-XX:+EliminateLocks。锁消除需要JVM工作在server模式下。
可重入锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,但不受影响。ReentrantLock 和synchronized 都是可重入锁。
public class Test implements Runnable{ public synchronized void get(){
System.out.println(Thread.currentThread().getId());
set();
} public synchronized void set(){
System.out.println(Thread.currentThread().getId());
} @Override
public void run() {
get();
}
public static void main(String[] args) {
Test ss=new Test();
new Thread(ss).start();
new Thread(ss).start();
new Thread(ss).start();
}
}
独占锁是一种悲观锁,synchronized就是一种独占锁,它假设最坏的情况,并且只有在确保其它线程不会造成干扰的情况下执行,会导致其它所有需要锁的线程挂起,等待持有锁的线程释放锁。而另一个更加有效的锁就是乐观锁。所谓乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。
Atomic类型的数据类型,如AtomicInteger
, AtomicLong
, AtomicReference
, AtomicBoolean等都可使用的是乐观锁。Atomic类型的实现是基于CAS算法的,由于需要同步的地方极少,也被称为轻量级锁。
分布式系统上还有分布式锁等。
对于多线程来说,死锁是非常严重的系统问题,必须修正。除了死锁,遇到很多的就是活跃度问题了。 活跃度问题主要包括:饥饿,丢失信号,和活锁等。
饥饿是指线程需要访问的资源被永久拒绝,以至于不能在继续进行。 比如说:某个权重比较低的线程可能一直不能够抢到CPU周期,从而一直不能够被执行。
也有一些场景是比较容易理解的。对于一个固定大小的连接池中,如果连接一直被用完,那么过多的任务可能由于一直无法抢占到连接从而不能够被执行。这也是饥饿的一种表现。
丢失信号比较好理解,thread1因为conditionA被wait,thread2因为conditionB被wait,另一线程调用notify而非notifyAll,thread1被唤醒,实际是conditionB满足了,应该是thread2被唤醒.这样thread1,thread2都无法正常运行。
活锁(Livelock)是指线程虽然没有被阻塞,但是由于某种条件不满足,一直尝试重试,却终是失败。
线程间的协同也有可能导致活锁。例如如果两个线程发生了某些条件的碰撞后重新执行,那么如果再次尝试后依然发生了碰撞,长此下去就有可能发生活锁。
解决活锁的一种方案是对重试机制引入一些随机性。例如如果检测到冲突,那么就暂停随机的一定时间进行重试。这回大大减少碰撞的可能性。
Java锁概念基础的更多相关文章
- Java基础之(一)——从synchronized优化看Java锁概念
一.悲观锁和乐观锁概念 悲观锁和乐观锁是一种广义的锁概念,Java中没有哪个Lock实现类就叫PessimisticLock或OptimisticLock,而是在数据并发情况下的两种不同处理策略. 针 ...
- Java 锁 概念介绍
一 Java中的锁是什么? /* * 一 Java锁定义? * 在计算机科学中,锁(lock)或互斥(mutex)是一种同步机制,用于在有许多执行线程的环境中强制对资源的访问限制. * 锁旨在强制 ...
- Java锁--框架
根据锁的添加到Java中的时间,Java中的锁,可以分为"同步锁"和"JUC包中的锁". 同步锁 即通过synchronized关键字来进行同步,实现对竞争资源 ...
- 【JAVA编码专题】JAVA字符编码系列一:Unicode,GBK,GB2312,UTF-8概念基础
这两天抽时间又总结/整理了一下各种编码的实际编码方式,和在Java应用中的使用情况,在这里记录下来以便日后参考. 为了构成一个完整的对文字编码的认识和深入把握,以便处理在Java开发过程中遇到的各种问 ...
- java锁与监视器概念 为什么wait、notify、notifyAll定义在Object中 多线程中篇(九)
在Java中,与线程通信相关的几个方法,是定义在Object中的,大家都知道Object是Java中所有类的超类 在Java中,所有的类都是Object,借助于一个统一的形式Object,显然在有些处 ...
- JAVA字符编码一:Unicode,GBK,GB2312,UTF-8概念基础
第一篇:JAVA字符编码系列一:Unicode,GBK,GB2312,UTF-8概念基础 来源:holen'blog 对字符编码与Unicode,ISO 10646,UCS,UTF8,UTF16, ...
- java 并发多线程显式锁概念简介 什么是显式锁 多线程下篇(一)
目前对于同步,仅仅介绍了一个关键字synchronized,可以用于保证线程同步的原子性.可见性.有序性 对于synchronized关键字,对于静态方法默认是以该类的class对象作为锁,对于实例方 ...
- -1-5 java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁 sleep()和wait()方法的区别 为什么wait(),notify(),notifyAll()等方法都定义在Object类中
本文关键词: java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁 sleep()和wait()方法的区别 为什么wait( ...
- Java中的锁概念
掌握Java中锁是Java多线程编程中绕不开的知识,只有知道理解Java各种锁才能在编码过程中灵活运用,写出更高效的多线程程序.而理解掌握锁的第一步,可从宏观上对比理解一下各种锁概念. 公平锁/非公平 ...
随机推荐
- Vijos P1131 最小公倍数和最大公约数问题【暴力】
最小公倍数和最大公约数问题 描述 输入二个正整数x0,y0(2≤x0≤100000,2≤y0≤1000000),求出满足下列条件的P.Q的个数. 条件:1.P.Q是正整数 2.要求P.Q以xO为最大公 ...
- BZOJ2004: [Hnoi2010]Bus 公交线路
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2004 状压dp+矩阵乘法. f[i][s]表示从第i位至前面的i-k位,第i位必须取的状态. ...
- MYSQL数据库增量备份
MySQL数据库增量备份,在这之前修改我们的数据库配置文件/etc/my.cnf开启bin-log日志功能即可.接下来是我参考了下网上的一些方法,自己写的,主要还是要能学到他的一些思路和方法. #fu ...
- UEP-级联查询
级联查询在UEP中采用动态下拉的形式,cascadeid为关键字,注意jsp页面的id的相互嵌套关系,数据库字段的数值的设置,和动态下拉SQL语句的书写.本功能实现了省市区的三级联动查询
- Java Thread wait、notify与notifyAll
Java的Object类包含了三个final方法,允许线程就资源的锁定状态进行通信.这三个方法分别是:wait(),notify(),notifyAll(),今天来了解一下这三个方法.在任何对象上调用 ...
- 关于atom
以前老听别人说atom这款编辑器如何如何的好用,今天特地试了下,结果一不小心将顶部的工具栏给隐藏了,弄了半天都没弄出来.后来就在网上到处寻找帮助,试试这个试试那个,终于弄好了,其实是这样的. 首先在任 ...
- 一键批量打印EXCEL、WORD文档
一键批量打印EXCEL.WORD文档,本方法也可以打印同一个文档N份,可以批量打印A3.A4文档,包括单.双面打印等.希望能帮到广大朋友.请大家注重原创版权,不得在未经许可的下转载.传播,或者用来对同 ...
- dede 内容页文章标题显示不全的更改方法
找到include/taglib/arclist.lib.php 1.$titlelen = AttDef($titlelen,30);换成$titlelen = AttDef($titlelen,2 ...
- [SinGuLaRiTy] 复习模板-图论
[SinGuLaRiTy-1041] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. 计算树的直径 //方法:任选一个点作为起点进行一次BFS ...
- mysql 性能优化常见命令
mysql 性能优化常见命令: 一: 当发现mysql程序运行缓慢时,在排除sql主机问题之后,可以尝试在schema,table,和sql上进一步进行考查: 1:mysql> show ful ...