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类型的数据类型,如AtomicIntegerAtomicLongAtomicReferenceAtomicBoolean等都可使用的是乐观锁。Atomic类型的实现是基于CAS算法的,由于需要同步的地方极少,也被称为轻量级锁。

  分布式系统上还有分布式锁等。

   

  对于多线程来说,死锁是非常严重的系统问题,必须修正。除了死锁,遇到很多的就是活跃度问题了。 活跃度问题主要包括:饥饿,丢失信号,和活锁等。 

  饥饿是指线程需要访问的资源被永久拒绝,以至于不能在继续进行。 比如说:某个权重比较低的线程可能一直不能够抢到CPU周期,从而一直不能够被执行。

  也有一些场景是比较容易理解的。对于一个固定大小的连接池中,如果连接一直被用完,那么过多的任务可能由于一直无法抢占到连接从而不能够被执行。这也是饥饿的一种表现。

  丢失信号比较好理解,thread1因为conditionA被wait,thread2因为conditionB被wait,另一线程调用notify而非notifyAll,thread1被唤醒,实际是conditionB满足了,应该是thread2被唤醒.这样thread1,thread2都无法正常运行。

  

  活锁(Livelock)是指线程虽然没有被阻塞,但是由于某种条件不满足,一直尝试重试,却终是失败。  

  线程间的协同也有可能导致活锁。例如如果两个线程发生了某些条件的碰撞后重新执行,那么如果再次尝试后依然发生了碰撞,长此下去就有可能发生活锁。  

  解决活锁的一种方案是对重试机制引入一些随机性。例如如果检测到冲突,那么就暂停随机的一定时间进行重试。这回大大减少碰撞的可能性。

Java锁概念基础的更多相关文章

  1. Java基础之(一)——从synchronized优化看Java锁概念

    一.悲观锁和乐观锁概念 悲观锁和乐观锁是一种广义的锁概念,Java中没有哪个Lock实现类就叫PessimisticLock或OptimisticLock,而是在数据并发情况下的两种不同处理策略. 针 ...

  2. Java 锁 概念介绍

    一   Java中的锁是什么? /* * 一 Java锁定义? * 在计算机科学中,锁(lock)或互斥(mutex)是一种同步机制,用于在有许多执行线程的环境中强制对资源的访问限制. * 锁旨在强制 ...

  3. Java锁--框架

    根据锁的添加到Java中的时间,Java中的锁,可以分为"同步锁"和"JUC包中的锁". 同步锁 即通过synchronized关键字来进行同步,实现对竞争资源 ...

  4. 【JAVA编码专题】JAVA字符编码系列一:Unicode,GBK,GB2312,UTF-8概念基础

    这两天抽时间又总结/整理了一下各种编码的实际编码方式,和在Java应用中的使用情况,在这里记录下来以便日后参考. 为了构成一个完整的对文字编码的认识和深入把握,以便处理在Java开发过程中遇到的各种问 ...

  5. java锁与监视器概念 为什么wait、notify、notifyAll定义在Object中 多线程中篇(九)

    在Java中,与线程通信相关的几个方法,是定义在Object中的,大家都知道Object是Java中所有类的超类 在Java中,所有的类都是Object,借助于一个统一的形式Object,显然在有些处 ...

  6. JAVA字符编码一:Unicode,GBK,GB2312,UTF-8概念基础

    第一篇:JAVA字符编码系列一:Unicode,GBK,GB2312,UTF-8概念基础 来源:holen'blog   对字符编码与Unicode,ISO 10646,UCS,UTF8,UTF16, ...

  7. java 并发多线程显式锁概念简介 什么是显式锁 多线程下篇(一)

    目前对于同步,仅仅介绍了一个关键字synchronized,可以用于保证线程同步的原子性.可见性.有序性 对于synchronized关键字,对于静态方法默认是以该类的class对象作为锁,对于实例方 ...

  8. -1-5 java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁 sleep()和wait()方法的区别 为什么wait(),notify(),notifyAll()等方法都定义在Object类中

     本文关键词: java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁  sleep()和wait()方法的区别 为什么wait( ...

  9. Java中的锁概念

    掌握Java中锁是Java多线程编程中绕不开的知识,只有知道理解Java各种锁才能在编码过程中灵活运用,写出更高效的多线程程序.而理解掌握锁的第一步,可从宏观上对比理解一下各种锁概念. 公平锁/非公平 ...

随机推荐

  1. [51nod1357]密码锁

    有一个密码锁,其有N位,每一位可以是一个0~9的数字,开启密码锁需要将锁上每一位数字转到解锁密码一致.这个类似你旅行用的行李箱上的密码锁,密码锁的每一位其实是一个圆形转盘,上面依次标了0,1,...9 ...

  2. BC#65 T5 ZYB's Prime

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=5594 完全不会啊TAT.. 其实官方题解已经说的很清楚了.. #include <cstdio> ...

  3. 关于python 2.7要求输出汉字问题

    对于python 2.7,使用print u'好好学习'会出现异常.可用以下作为汉字输出,获取数据(字符串)时,用unicode(str, "utf8")生成unicode对象 p ...

  4. 最长上升子序列(LIS) dp学习~3

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1087 Super Jumping! Jumping! Jumping! Time Limit: 200 ...

  5. POI Sax 事件驱动解析Excel2007文件

    Excel2007版本的代码如下,本文主要是用于POI解析大文件Excel容易出现内存溢出的现象而提出解决方案,故此解决了大数据量的Excel文件解析的难度,在此拿出来贡献给大家,谢谢! 里面用到的相 ...

  6. ECharts 环形饼图 动态获取json数据

    ECharts  环形饼图 动态获取json数据 效果图如下: 一.html部分 <div id="secondPieChart" style="width:100 ...

  7. [国嵌笔记][036][关闭MMU和CACHE]

    关闭MMU和CACHE 1.Cache是一种容量小,但存取速度非常快的存储器,它保存最近用到的存储器中数据的拷贝.按功能分为ICache(指令Cache)和DCache(数据Cache) 2.虚拟地址 ...

  8. Android开发——BroadcastReceiver广播的使用

    想要了解广播定义及相关原理的可以看下这一篇BroadcastReceiver史上最全面解析 简单地对广播进行分类吧,广播有两个角色,一个是广播发送者,另外一个是广播接收者 广播按照类型分为两种,一种是 ...

  9. final、finally、finalize

    final是一个修饰词.可以修饰变量.方法.类 final修饰变量时分为两种 )1.修饰成员变量:该成员变量不可以被二次赋值.也就是说成员变量无法改变.且该成员变量要么在定义时初始化,要么在构造器中进 ...

  10. 用php怎样将图片gif转化为jpg

    <?php $input= "link2.gif"; $output='test.jpg' ; $image=imagecreatefromgif($input); imag ...