Java 隐式锁 - synchronized 关键字

Java 中关键字 synchronized 表示只有一个线程可以获取作用对象的锁,执行代码,阻塞其他线程。

作用:

  • 确保线程互斥地访问同步代码
  • 保证共享变量的修改能够及时可见
  • 有效解决重排序问题

用法:

  • 修饰普通方法
  • 修饰静态方法
  • 指定对象,修饰代码块

特点:

  • 阻塞未获取到锁、竞争同一个对象锁的线程
  • 获取锁无法设置超时
  • 无法实现公平锁
  • 控制等待和唤醒需要结合加锁对象的 wait() 和 notify()、notifyAll()
  • 锁的功能是 JVM 层面实现的
  • 在加锁代码块执行完或者出现异常,自动释放锁

原理:

  • 同步代码块是通过 monitorenter 和 monitorexit 指令获取线程的执行权
  • 同步方法通过加 ACC_SYNCHRONIZED 标识实现线程的执行权的控制

测试代码:

public class TestSynchronized {

    public void sync() {
        synchronized (this) {
            System.out.println("sync");
        }
    }

    public synchronized void syncdo() {
        System.out.println("syncdo");
    }

    public static synchronized void staticSyncdo() {
        System.out.println("staticSyncdo");
    }
}

通过JDK 反汇编指令 javap -c -v TestSynchronized

javap -c -v TestSynchronized

  Last modified 2019-5-27; size 719 bytes
  MD5 checksum e5058a43e76fe1cff6748d4eb1565658
  Compiled from "TestSynchronized.java"
public class constxiong.interview.TestSynchronized
  minor version: 0
  major version: 49
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Class              #2             // constxiong/interview/TestSynchronized
   #2 = Utf8               constxiong/interview/TestSynchronized
   #3 = Class              #4             // java/lang/Object
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Utf8               Code
   #8 = Methodref          #3.#9          // java/lang/Object."<init>":()V
   #9 = NameAndType        #5:#6          // "<init>":()V
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lconstxiong/interview/TestSynchronized;
  #14 = Utf8               sync
  #15 = Fieldref           #16.#18        // java/lang/System.out:Ljava/io/PrintStream;
  #16 = Class              #17            // java/lang/System
  #17 = Utf8               java/lang/System
  #18 = NameAndType        #19:#20        // out:Ljava/io/PrintStream;
  #19 = Utf8               out
  #20 = Utf8               Ljava/io/PrintStream;
  #21 = String             #14            // sync
  #22 = Methodref          #23.#25        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #23 = Class              #24            // java/io/PrintStream
  #24 = Utf8               java/io/PrintStream
  #25 = NameAndType        #26:#27        // println:(Ljava/lang/String;)V
  #26 = Utf8               println
  #27 = Utf8               (Ljava/lang/String;)V
  #28 = Utf8               syncdo
  #29 = String             #28            // syncdo
  #30 = Utf8               staticSyncdo
  #31 = String             #30            // staticSyncdo
  #32 = Utf8               SourceFile
  #33 = Utf8               TestSynchronized.java
{
  public constxiong.interview.TestSynchronized();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #8                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lconstxiong/interview/TestSynchronized;

  public void sync();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=1
         0: aload_0
         1: dup
         2: astore_1
         3: monitorenter
         4: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;
         7: ldc           #21                 // String sync
         9: invokevirtual #22                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        12: aload_1
        13: monitorexit
        14: goto          20
        17: aload_1
        18: monitorexit
        19: athrow
        20: return
      Exception table:
         from    to  target type
             4    14    17   any
            17    19    17   any
      LineNumberTable:
        line 6: 0
        line 7: 4
        line 6: 12
        line 9: 20
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      21     0  this   Lconstxiong/interview/TestSynchronized;

  public synchronized void syncdo();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_SYNCHRONIZED
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #29                 // String syncdo
         5: invokevirtual #22                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 12: 0
        line 13: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  this   Lconstxiong/interview/TestSynchronized;

  public static synchronized void staticSyncdo();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED
    Code:
      stack=2, locals=0, args_size=0
         0: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #31                 // String staticSyncdo
         5: invokevirtual #22                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 16: 0
        line 17: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
}
SourceFile: "TestSynchronized.java"




Java面试题汇总,总有一道卡住你!

原文地址:https://www.cnblogs.com/ConstXiong/p/11687745.html

时间: 2024-10-12 07:53:18

Java 隐式锁 - synchronized 关键字的相关文章

JAVA多线程之Synchronized关键字--对象锁的特点

一,介绍 本文介绍JAVA多线程中的synchronized关键字作为对象锁的特点. 二,分析 synchronized可以修饰实例方法,如下形式: 1 public class MyObject { 2 3 synchronized public void methodA() { 4 //do something.... 5 } 这里,synchronized 关键字锁住的是当前对象.这也是称为对象锁的原因. 为啥锁住当前对象?因为 methodA()是个实例方法,要想执行methodA(),

JAVA线程安全之synchronized关键字的正确用法

JAVA线程安全关于synchronized关键字的用法,今天才知道原来我一直错了.以为用了synchronized关键字包住了代码就可以线程同步安全了. 测试了下.发现是完全的错了.synchronized必须正确的使用才是真正的线程安全...虽然知道这种写法,一直以为却由于懒而用了错误的方法. 看来基础还没有打好.仍需复习加强!工作中犯这种错误是不可原谅的,要知道使用synchronized关键字的地方都是数据敏感的!汗一把... 先贴代码: [java] view plaincopypri

innodB的隐式锁

http://blog.csdn.net/taozhi20084525/article/details/19545231 一.知识准备之隐式锁 参考:http://www.uml.org.cn/sjjm/201205302.asp Innodb 实现了一个延迟加锁的机制,来减少加锁的数量,在代码中称为隐式锁(Implicit Lock).隐式锁中有个重要的元素,事务ID(trx_id).隐式锁的逻辑过程如下: A. InnoDB的每条记录中都一个隐含的trx_id字段,这个字段存在于簇索引的B+

隐式锁

Lock 是一种悲观的顺序化机制.它假设很可能发生冲突,因此在操作数据时,就加锁.如果冲突的可能性很小,多数的锁都是不必要的. Innodb 实现了一个延迟加锁的机制,来减少加锁的数量,在代码中称为隐式锁(Implicit Lock).隐式锁中有个重要的元素,事务ID(trx_id). 隐式锁的逻辑过程如下:A. InnoDB的每条记录中都一个隐含的trx_id字段,这个字段存在于簇索引的B+Tree中.B. 在操作一条记录前,首先根据记录中的trx_id检查该事务是否是活动的事务(未提交或回滚

搜狗一道java题目 关于对象 synchronized 关键字作用在 int, integer

第一次见到这个题目,我觉得自己没学到java,太浅了,其实这个问题没有考synchronized关键字,只是考什么是对象? 1.在java编程思想的第二章有一句话; 一切都是对象,很可惜int,char 等不是的,虽然他们有他们的包装类,但是java还是保留了int 这些好用的原子类型, 对于synchronized后面可以跟对象和.class所以 字符串是对象可以,Integer对象可以,ExampleCLass.class可以. 我想问的是,数组是对象吗? 查了一下,是对象,所以数组也是答案

Java显式锁学习总结之二:使用AbstractQueuedSynchronizer构建同步组件

Jdk1.5中包含了并发大神Doug Lea写的并发工具包java.util.concurrent,这个工具包中包含了显示锁和其他的实用同步组件.Doug Lea在构建锁和组件的时候,大多是以队列同步器(AbstractQueuedSynchronizer)为基础的,因此AbstractQueuedSynchronizer可以看作是并发包的基础框架.因此掌握了AbstractQueuedSynchronizer的实现原理,也就掌握了大多数并发组件的实现原理. AbstractQueuedSync

Java显式锁学习总结之一:概论

我们都知道在java中,当多个线程需要并发访问共享资源时需要使用同步,我们经常使用的同步方式就是synchronized关键字,事实上,在jdk1.5之前,只有synchronized一种同步方式.而在jdk1.5中提供了一种新的同步方式--显示锁(Lock).显示锁是随java.util.concurrent包一起发布的,java.util.concurrent包是并发大神Doug Lea写的一个并发工具包,里面除了显示锁,还有许多其他的实用并发工具类. 什么是显示锁 什么是显示锁?用一段代码

Java基础之线程synchronized关键字

synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块 1. synchronized 方法:通过在方法声明中加入 synchronized关键字来声明 synchronized 方法.如:  public synchronized void accessVal(int newVal);  synchronized 方法控制对类成员变量的访问:每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执

Java多线程4:synchronized关键字

原文:http://www.cnblogs.com/skywang12345/p/3479202.html 1. synchronized原理在java中,每一个对象有且仅有一个同步锁.这也意味着,同步锁是依赖于对象而存在.当我们调用某对象的synchronized方法时,就获取了该对象的同步锁.例如,synchronized(obj)就获取了“obj这个对象”的同步锁.不同线程对同步锁的访问是互斥的.也就是说,某时间点,对象的同步锁只能被一个线程获取到!通过同步锁,我们就能在多线程中,实现对“