锁的种类

锁的种类

Java中锁的种类大致分为偏向锁,自旋锁,轻量级锁,重量级锁。
  锁的使用方式为:先提供偏向锁,如果不满足的时候,升级为轻量级锁,再不满足,升级为重量级锁。自旋锁是一个过渡的锁状态,不是一种实际的锁类型。
  锁只能升级,不能降级。

偏向锁

是一种编译解释锁。如果代码中不可能出现多线程并发争抢同一个锁的时候,JVM编译代码,解释执行的时候,会自动的放弃同步信息。消除synchronized的同步代码结果。使用锁标记的形式记录锁状态。在Monitor中有变量ACC_SYNCHRONIZED。当变量值使用的时候,代表偏向锁锁定。可以避免锁的争抢和锁池状态的维护。提高效率。

自旋锁

是一个过渡锁,是偏向锁和轻量级锁的过渡。
  当获取锁的过程中,未获取到。为了提高效率,JVM自动执行若干次空循环,再次申请锁,而不是进入阻塞状态的情况。称为自旋锁。自旋锁提高效率就是避免线程状态的变更。

轻量级锁

过渡锁。当偏向锁不满足,也就是有多线程并发访问,锁定同一个对象的时候,先提升为轻量级锁。也是使用标记ACC_SYNCHRONIZED标记记录的。ACC_UNSYNCHRONIZED标记记录未获取到锁信息的线程。就是只有两个线程争抢锁标记的时候,优先使用轻量级锁。
  两个线程也可能出现重量级锁。

重量级锁

下面说的实现就是重量级锁

锁的底层实现

Java 虚拟机中的同步(Synchronization)基于进入和退出管程(Monitor)对象实现。同步方法 并不是由 monitor enter 和 monitor exit 指令来实现同步的,而是由方法调用指令读取运行时常量池中方法的 ACC_SYNCHRONIZED 标志来隐式实现的。

当在对象上加锁时,数据是记录在对象头中。当执行synchronized同步方法或同步代码块时,会在对象头中记录锁标记,锁标记指向的是monitor对象(也称为管程或监视器锁)的起始地址。每个对象都存在着一个 monitor 与之关联,对象与其 monitor 之间的关系有存在多种实现方式,如monitor可以与对象一起创建销毁当线程试图获取对象锁时自动生成,但当一个 monitor 被某个线程持有后,它便处于锁定状态。
在Java虚拟机(HotSpot)中,monitor是由ObjectMonitor实现的。
ObjectMonitor中有两个队列,_WaitSet 和 _EntryList,以及_Owner标记。其中_WaitSet是用于管理等待队列(wait)线程的,_EntryList是用于管理锁池阻塞线程的,_Owner标记用于记录当前执行线程。

过程:

当多线程并发访问同一个同步代码时,首先会进入_EntryList,当线程获取锁标记后,monitor中的_Owner记录此线程,并在monitor中的计数器执行递增计算(+1),代表锁定,其他线程在_EntryList中继续阻塞。若执行线程调用wait方法,则monitor中的计数器执行赋值为0计算,并将_Owner标记赋值为null,代表放弃锁,执行线程进如_WaitSet中阻塞。若执行线程调用notify/notifyAll方法,_WaitSet中的线程被唤醒,进入_EntryList中阻塞,等待获取锁标记。若执行线程的同步代码执行结束,同样会释放锁标记,monitor中的_Owner标记赋值为null,且计数器赋值为0计算。

PS

对象头:存储对象的hashCode、锁信息或分代年龄或GC标志,类型指针指向对象的类元数据,JVM通过这个指针确定该对象是哪个类的实例等信息。
实例变量:存放类的属性数据信息,包括父类的属性信息
填充数据:由于虚拟机要求对象起始地址必须是8字节的整数倍。填充数据不是必须存在的,仅仅是为了字节对齐

ReentrantLock

重入锁,建议应用的同步方式。相对效率比synchronized高。量级较轻。(synchronized在JDK1.5版本开始,尝试优化。到JDK1.7版本后,优化效率已经非常好了。在绝对效率上,不比reentrantLock差多少)
使用重入锁,必须必须必须手工释放锁标记。一般都是在finally代码块中定义释放锁标记的unlock方法。

公平锁

private static ReentrantLock lock = new ReentrantLock(true);

尝试锁

void m2(){
        boolean isLocked = false;
        try{
            // 尝试锁, 如果有锁,无法获取锁标记,返回false。
            // 如果获取锁标记,返回true
            // isLocked = lock.tryLock();

            // 阻塞尝试锁,阻塞参数代表的时长,尝试获取锁标记。
            // 如果超时,不等待。直接返回。
            isLocked = lock.tryLock(5, TimeUnit.SECONDS);
            if(isLocked){
                System.out.println("m2() method synchronized");
            }else{
                System.out.println("m2() method unsynchronized");
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            if(isLocked){
                // 尝试锁在解除锁标记的时候,一定要判断是否获取到锁标记。
                // 如果当前线程没有获取到锁标记,会抛出异常。
                lock.unlock();
            }
        }
    }

原文地址:https://www.cnblogs.com/RobertLionLin/p/11423156.html

时间: 2024-11-13 02:27:12

锁的种类的相关文章

java锁的种类以及辨析(转载)

java锁的种类以及辨析(一):自旋锁 锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchronized 和 ReentrantLock等等 ) .这些已经写好提供的锁为我们开发提供了便利,但是锁的具体性质以及类型却很少被提及.本系列文章将分析JAVA下常见的锁名称以及特性,为大家答疑解惑. 1.自旋锁 自旋锁是采用让当前线程不停地的在循环体内执行实现的,当循环的条件被其他线程改变时 才能进入临界区.如下 01 public class SpinLock { 02  

锁的种类,阻塞,死锁产生与解决办法。

TM锁的种类: TM锁几种模式的互斥关系: 阻塞 定义:当一个会话保持另一个会话正在请求的资源上的锁定时,就会发生阻塞.被阻塞的会话将一直挂起,直到持有锁的会话放弃锁定的资源为止.4个常见的dml语句会产生阻塞INSERTUPDATEDELETESELECT-FOR UPDATE -------------------------------------------------------------- update 的阻塞     试验: 1.    获得会话sid SQL> select s

(转)SQL SERVER的锁机制(一)——概述(锁的种类与范围)

锁定:通俗的讲就是加锁.锁定是 Microsoft SQL Server 数据库引擎用来同步多个用户同时对同一个数据块的访问的一种机制. 定义:当有事务操作时,数据库引擎会要求不同类型的锁定,如相关数据行.数据页或是整个数据表,当锁定运行时,会阻止其他事务对已经锁定的数据行.数据页或数据表进行操作.只有在当前事务对于自己锁定的资源不在需要时,才会释放其锁定的资源,供其他事务使用. 一.锁的种类与范围(如下表) 锁类型 说明 共享 (S) 用于不更改或不更新数据的读取操作,如 SELECT 语句.

SQL SERVER的锁机制(一)——概述(锁的种类与范围)

锁定:通俗的讲就是加锁.锁定是 Microsoft SQL Server 数据库引擎用来同步多个用户同时对同一个数据块的访问的一种机制. 定义:当有事务操作时,数据库引擎会要求不同类型的锁定,如相关数据行.数据页或是整个数据表,当锁定运行时,会阻止其他事务对已经锁定的数据行.数据页或数据表进行操作.只有在当前事务对于自己锁定的资源不在需要时,才会释放其锁定的资源,供其他事务使用. 一.锁的种类与范围(如下表) 锁类型 说明 共享 (S) 用于不更改或不更新数据的读取操作,如 SELECT 语句.

Java锁的种类以及辨析

锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchronized 和 ReentrantLock等等 ) .这些已经写好提供的锁为我们开发提供了便利,但是锁的具体性质以及类型却很少被提及.本系列文章将分析JAVA中常见的锁以及其特性,为大家答疑解惑. 1.自旋锁 2.自旋锁的其他种类 3.阻塞锁 4.可重入锁 5.读写锁 6.互斥锁 7.悲观锁 8.乐观锁 9.公平锁 10.非公平锁 11.偏向锁 12.对象锁 13.线程锁 14.锁粗化 15.轻量级锁 16.锁消除

Java锁的种类

1.自旋锁 自旋锁是采用让当前线程不停地的在循环体内执行实现的,当循环的条件被其他线程改变时 才能进入临界区.如下 public class SpinLock { private AtomicReference<Thread> sign =new AtomicReference<>(); public void lock(){ Thread current = Thread.currentThread(); while(!sign .compareAndSet(null, curr

多线程编程-- part5 锁的种类以及辨析

java中的锁,可以分为同步锁和JUC包中的锁. 同步锁 通过synchronized关键字进行同步,实现对竞争资源的互斥访问的锁,. 原理:对于每一个对象,有且只有一个同步锁,在同一时间点,所有的线程中有且只有一个能获取该同步锁,获取到同步锁的就可以被CPU进行调度,其他线程必须等待,直到获取到同步锁之后才能继续运行,这就是多线程通过同步锁进行同步的原理. JUC包中的锁:java.util.concurrent 功能更强大,使用当然更复杂. JUC包中锁,包括:lock接口,readWrit

java锁的种类以及辨析(一):自旋锁

锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchronized 和 ReentrantLock等等 ) .这些已经写好提供的锁为我们开发提供了便利,但是锁的具体性质以及类型却很少被提及.本系列文章将分析JAVA下常见的锁名称以及特性,为大家答疑解 惑. 1.自旋锁 自旋锁是采用让当前线程不停地的在循环体内执行实现的,当循环的条件被其他线程改变时 才能进入临界区.如下 01 public class SpinLock { 02   03   private Atomi

Objective-C 关于锁的种类

Objective-C中不同方式实现锁(一) 转载http://www.tanhao.me/pieces/616.html/ 为什么需要使用锁,当然熟悉多线程的你,自然不会对它觉得陌生. 那你在代码中是否很好的使用了锁的机制呢?你又知道几种实现锁的方法呢? 今天一起来探讨一下Objective-C中几种不同方式实现的锁,在这之前我们先构建一个测试用的类,假想它是我们的一个共享资源,method1与method2是互斥的,代码如下: 12345678910111213 @implementatio