Java中的synchronized关键字

目录
  • 1、synchronized锁的底层实现原理
  • 2、基于synchronized实现单例模式
  • 3、利用类加载实现单例模式(饿汉模式)

1、synchronized锁的底层实现原理

JVM基于进入和退出Monitor对象来实现方法同步和代码块同步。代码块同步是使用monitorentermonitorexit指令实现的,monitorenter指令是在编译后插入到同步代码块的开始位置,而monitorexit是插入到方法结束处和异常处。任何对象都有一个monitor与之关联,当且一个monitor被持有后,它将处于锁定状态。

根据虚拟机规范的要求,在执行monitorenter指令时,首先要去尝试获取对象的锁,如果这个对象没被锁定,或者当前线程已经拥有了那个对象的锁,把锁的计数器加1;相应地,在执行monitorexit指令时会将锁计数器减1,当计数器被减到0时,锁就释放了。如果获取对象锁失败了,那当前线程就要阻塞等待,直到对象锁被另一个线程释放为止。

如何判断这个对象是否被锁定?对象头中的MarkWord字段记录了该对象的锁信息。

2、基于synchronized实现单例模式

public class Singleton {
    private volatile static Singleton uniqueInstance;

    private Singleton(){

    }
    public static Singleton getUniqueInstance() {
        //没有实例化才加锁
        if (uniqueInstance == null) {
            //给类对象加锁
            synchronized (Singleton.class) {
                if (uniqueInstance == null)
                    uniqueInstance = new Singleton();
            }
        }
        return uniqueInstance;
    }

//    public static synchronized Singleton getUniqueInstance(){
//        if(uniqueInstance==null){
//            uniqueInstance = new Singleton();
//        }
//        return uniqueInstance;
//    }
}

首先说一下为什么不采用第二种方式实现单例:不管该对象是否已经实例化,都要调用这个同步方法,会导致大量的线程进入阻塞;而采用双重锁检验,可以在第一次判断不为空的时候就直接返回,不用进入同步代码块。

几个要点:

  • 为什么uniqueInstance属性要用volatile修饰?new操作并非一个原子性操作,分为三个步骤(分配对象的内存空间、初始化对象、设置uniqueInstance指向刚分配的内存地址),如果不使用volatile,2和3之间可能发生指令重排,导致外部访问到一个还没有初始化的对象。
  • 为什么构造方法时私有的?防止对象在其他地方被创建。
  • 为什么uniqueInstance是私有静态的?私有使得外部只能通过特定的方式去访问对象,静态是因为要在静态方法中访问该对象。
  • 为什么getUniqueInstance()方式是公共、静态的?public使得外界统一通过访问该方法获得对象,static使得程序可以通过类名获取对象。
  • 为什么采用双重检测初始化对象?第一次检测主要用来判断对象是否已经创建,如果已创建则直接返回;第二次检测是因为:可能有多个线程在第一次检测中发现对象为空,同时进入同步代码块,但只有一个线程会抢到锁并创建对象,其他线程阻塞排队等待锁的释放。当创建对象的线程返回后,阻塞的线程会被唤醒,这时候对象已经不为空,所以需要第二次检测来阻止对象的多次创建。

3、利用类加载实现单例模式(饿汉模式)

public class SingleTon2 {
/** 内置对象是静态的,并且直接创建对象,保证对象在初始化时加载完成 */
    public static SingleTon2 instance = new SingleTon2(); 

/** 构造方法私有,防止对象在其他地方被创建 */
    private SingleTon2(){

    }

/** 公共静态方法返回对象 */
    public static SingleTon2 getInstance(){

        return instance;
    }
}

到此这篇关于Java中的synchronized关键字的文章就介绍到这了,更多相关synchronized关键字内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 深入分析JAVA Synchronized关键字

    并发一致性的概念? 是利用锁的机制来实现同步的,锁机制有如下两种特性: 互斥性:即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程中的协调机制,这样在同一时间只有一个线程对需同步的代码块(复合操作)进行访问.互斥性我们也往往称为操作的原子性. 可见性:必须确保在锁被释放之前,对共享变量所做的修改,对于随后获得该锁的另一个线程是可见的(即在获得锁时应获得最新共享变量的值),否则另一个线程可能是在本地缓存的某个副本上继续操作从而引起不一致. Synchronized的用法? 1.同步

  • Java的Synchronized关键字学习指南(全面 & 详细)

    前言 在Java中,有一个常被忽略 但 非常重要的关键字Synchronized今天,我将详细讲解 Java关键字Synchronized的所有知识,希望你们会喜欢 目录 1. 定义 Java中的1个关键字 2. 作用 保证同一时刻最多只有1个线程执行 被Synchronized修饰的方法 / 代码 其他线程 必须等待当前线程执行完该方法 / 代码块后才能执行该方法 / 代码块 3. 应用场景 保证线程安全,解决多线程中的并发同步问题(实现的是阻塞型并发),具体场景如下: 修饰 实例方法 / 代

  • Java中关键字synchronized的使用方法详解

    synchronized是Java里的一个关键字,起到的一个效果是"监视器锁"~~,它的功能就是保证操作的原子性,同时禁止指令重排序和保证内存的可见性! public class TestDemo { static class Counter{ public int count = 0; public void add(){ count++; } } public static void main(String[] args) throws InterruptedException {

  • Java多线程之synchronized关键字的使用

    一.使用在非静态方法上 public synchronized void syzDemo(){ System.out.println(System.currentTimeMillis()); System.out.println("进入synchronized锁:syzDemo"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } 二.使用在静态方法上 publi

  • Java synchronized关键字使用方式及特性解析

    这篇文章主要介绍了Java synchronized关键字使用方式及特性解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 synchronized 关键字是实现锁的一种方式,是在jvm层面实现的非公平锁,以下是使用synchronized的四种方式 synchronized 特性: 1.非公平锁 2.可重入性 1.作用在方法上,保证了访问同一个对象的同一个方法的线程同步 public synchronized void testFun(Str

  • Java synchronized关键字和Lock接口实现原理

    这篇文章主要介绍了Java synchronized关键字和Lock接口实现原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 引用 当开发过程中,我们遇到并发问题.怎么解决? 一种解决方式,简单粗暴:上锁.将千军万马都给拦下来,只允许一个人过独木桥.书面意思就是将并行的程序变成串行的程序.现实的锁有门锁.挂锁和抽屉锁等等.在Java中,我们的锁就是synchronized关键字和Lock接口. synchronized关键字 synchron

  • java中synchronized关键字的3种写法实例

    目录 预备知识 写法一:修饰代码块  写法二:修饰方法 写法三:修饰静态方法 synchronized原理 1. monitor锁定过程 2. synchronized锁 3. synchronized锁优化 总结 预备知识 首先,我们得知道在java中存在三种变量: 实例变量 ==> 存在于堆中 静态变量 ==> 存在于方法区中 局部变量 ==> 存在于栈中 然后,我们得明白,合适会发生高并发不安全 条件1:多线程并发. 条件2:有共享数据. 条件3:共享数据有修改的行为. 具体不安全

  • Java中的synchronized关键字

    目录 1.synchronized锁的底层实现原理 2.基于synchronized实现单例模式 3.利用类加载实现单例模式(饿汉模式) 1.synchronized锁的底层实现原理 JVM基于进入和退出Monitor对象来实现方法同步和代码块同步.代码块同步是使用monitorenter和monitorexit指令实现的,monitorenter指令是在编译后插入到同步代码块的开始位置,而monitorexit是插入到方法结束处和异常处.任何对象都有一个monitor与之关联,当且一个moni

  • 详解java中的synchronized关键字

    Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行.另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块. 二.然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块.

  • 深入理解java中的synchronized关键字

    synchronized 关键字,代表这个方法加锁,相当于不管哪一个线程A每次运行到这个方法时,都要检查有没有其它正在用这个方法的线程B(或者C D等),有的话要等正在使用这个方法的线程B(或者C D)运行完这个方法后再运行此线程A,没有的话,直接运行它包括两种用法:synchronized 方法和 synchronized 块. 1. synchronized 方法:通过在方法声明中加入 synchronized关键字来声明 synchronized 方法.如: 复制代码 代码如下: publ

  • 实例解析Java中的synchronized关键字与线程安全问题

    首先来回顾一下synchronized的基本使用: synchronized代码块,被修饰的代码成为同步语句块,其作用的范围是调用这个代码块的对象,我们在用synchronized关键字的时候,能缩小代码段的范围就尽量缩小,能在代码段上加同步就不要再整个方法上加同步.这叫减小锁的粒度,使代码更大程度的并发. synchronized方法,被修饰的方法成为同步方法,其作用范围是整个方法,作用对象是调用这个方法的对象. synchronized静态方法,修饰一个static静态方法,其作用范围是整个

  • Java中使用synchronized关键字实现简单同步操作示例

    简单记录下java中synchronized关键字的使用方法. 在介绍之前需要明确下java中的每一个类的对象实例都有且只有一个锁(lock)和之相关联,synchronized关键字只作用于该锁,即可以认为synchronized只对java类的对象实例起作用. synchronized修饰函数 复制代码 代码如下: public synchronized aMethod(){ } 这就是最常用的情景,那么这个同步方法的用途是啥,为了方便就记作aMethod方法. 1.synchronized

  • 如何在JAVA中使用Synchronized

    <编程思想之多线程与多进程(1)--以操作系统的角度述说线程与进程>一文详细讲述了线程.进程的关系及在操作系统中的表现,这是多线程学习必须了解的基础.本文将接着讲一下Java线程同步中的一个重要的概念synchronized. 在Java中,synchronized关键字是用来控制线程同步的,就是在多线程的环境下,控制synchronized代码段不被多个线程同时执行. synchronized是Java中的关键字,是一种同步锁.它修饰的对象有以下几种: 1. 修饰一个代码块,被修饰的代码块称

  • 深入理解Java中的volatile关键字(总结篇)

    基本概念 -------------------------------------------------------------------------------- 先补充一下概念:Java 内存模型中的可见性.原子性和有序性. 可见性: 可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉.通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值,有时甚至是根本不可能的事情.为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制. 可见性,是指线程之间的可见性,一个

  • 解析Java中的static关键字

    一.static关键字使用场景 static关键字主要有以下5个使用场景: 1.1.静态变量 把一个变量声明为静态变量通常基于以下三个目的: 作为共享变量使用 减少对象的创建 保留唯一副本 第一种比较容易理解,由于static变量在内存中只会存在一个副本,所以其可以作为共享变量使用,比如要定义一个全局配置.进行全局计数.如: public class CarConstants { // 全局配置,一般全局配置会和final一起配合使用, 作为共享变量 public static final in

  • Java中提供synchronized后为什么还要提供Lock

    目录 一.为何提供Lock接口? 二.死锁问题 三.synchronized的局限性 四.解决问题  摘要: 在Java中提供了synchronized关键字来保证只有一个线程能够访问同步代码块.既然已经提供了synchronized关键字,那为何在Java的SDK包中,还会提供Lock接口呢?这是不是重复造轮子,多此一举呢?今天,我们就一起来探讨下这个问题. 在Java中提供了synchronized关键字来保证只有一个线程能够访问同步代码块.既然已经提供了synchronized关键字,那为

  • Java多线程并发synchronized 关键字

    目录 基础 修饰普通方法 修饰静态方法 Synchronized 加锁原理 monitorenter monitorexit synchronized 修饰静态方法 优点.缺点及优化 其他说明 基础 Java 在虚拟机层面提供了 synchronized 关键字供开发者快速实现互斥同步的重量级锁来保障线程安全. synchronized 关键字可用于两种场景: 修饰方法. 持有一个对象,并执行一个代码块. 而根据加锁的对象不同,又分为两种情况: 对象锁 类对象锁 以下代码示例是 synchron

随机推荐