首页 > 编程语言 >Java synchronized

Java synchronized

时间:2023-01-05 14:23:53浏览次数:42  
标签:Java Monitor synchronized Thread 线程 println NULL

synchronized是java提供线程间同步的重要机制
保证在同一时刻, 被修饰的代码块或方法只会有一个线程执行,以达到保证并发安全的效果

java内存模型:
image

先通过一个生产者消费者例子来了解如何使用synchronized

package com.example.demo;

public class SyncTest {
    static Object obj = new Object();
    static boolean flag = false;
    public static void main(String[] args) throws InterruptedException {
        Thread c1 = new Thread(new Consumer());
        Thread p1 = new Thread(new Producer());
        c1.start();
        Thread.sleep(1000);
        p1.start();

        c1.join();
        p1.join();
    }

    static class Consumer implements Runnable {

        @Override
        public void run() {
            synchronized (obj) {
                System.out.println("Consumer executing...");
                while (!flag) {
                    System.out.println("no product, waiting");
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("Consumer waiting end....");
                }
                flag = false;
                System.out.println("consuming.....");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("exit consumer.....");
            }
        }
    }

    static class Producer implements Runnable {

        @Override
        public void run() {
            synchronized (obj) {
                System.out.println("Producer executing......");
                try {
                    System.out.println("Producing.....");
                    Thread.sleep(2000);
                    flag = true;
                    obj.notify();
                    Thread.sleep(2000);
                    System.out.println("Producer exit......");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

当然上面是代码块的方式,另一种方式是用在方法上。

  • synchronized锁的是谁?
  • 锁是如何实现的?
  • wait()和notify()发生了什么?

synchronized锁的是谁?

synchronized有两种使用方式,分别来进行讨论

  1. 代码块
    我们知道,使用代码块的时候synchronized后面要传入一个对象(Object)或者类(obj.class),所以结论就是传的是谁锁的就是谁。
  2. 方法
    方法又分为静态方法和非静态方法
  • 静态方法:锁的是方法所在的类
  • 非静态方法:锁的是调用该方法的对象

锁是如何实现的?

关键词:Monitor对象,monitorenter和monitorexit指令,markword
monitor:每个对象都是一个监视器锁(monitor),当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权。
Synchronized 是通过对象内部的一个叫做监视器锁(monitor)来实现的,监视器锁本质又是依赖于底层的操作系统的 Mutex Lock(互斥锁)来实现的。而操作系统实现线程之间的切换需要从用户态转换到核心态,这个成本非常高,状态之间的转换需要相对比较长的时间,这就是为什么 Synchronized 效率低的原因。因此,这种依赖于操作系统 Mutex Lock 所实现的锁我们称之为 “重量级锁”。
再具体一点,Monitor是由ObjectMonitor实现的,其源码是用C++语言编写的,

// src/share/vm/runtime/objectMonitor.hpp
ObjectMonitor() {
    _header       = NULL;
    _count        = 0;  //锁的计数器,获取锁时count数值加1,释放锁时count值减1
    _waiters      = 0,  //等待线程数
    _recursions   = 0;  // 线程重入次数
    _object       = NULL;  // 存储Monitor对象
    _owner        = NULL;  // 持有当前线程的owner
    _WaitSet      = NULL;  // wait状态的线程列表
    _WaitSetLock  = 0 ;
    _Responsible  = NULL ;
    _succ         = NULL ;
    _cxq          = NULL ;  // 阻塞在EntryList上的单向线程列表
    FreeNext      = NULL ;
    _EntryList    = NULL ;  // 处于等待锁状态block状态的线程列表
    _SpinFreq     = 0 ;
    _SpinClock    = 0 ;
    OwnerIsThread = 0 ;
    _previous_owner_tid = 0;
  }

image

获取Monitor和释放Monitor的流程如下:

当多个线程同时访问同步代码块时,首先会找到对象或类对应的Monitor对象,进入到EntryList中,然后通过CAS的方式尝试将Monitor中的owner字段设置为当前线程,如果成功count加1;如果之前的owner的值就是指向当前线程的,owner和recursions都需要加1。如果CAS尝试获取锁失败,则进入到EntryList中。

当获取锁的线程调用wait()方法(只有获取到锁才能用wait方法),则会将owner设置为null,同时count减1,recursions减1,当前线程加入到WaitSet中,等待被唤醒。

当前线程执行完同步代码块时,则会释放锁,count减1,recursions减1。当recursions的值为0时,说明线程已经释放了锁。

wait(), notify()

Jdk1.6为什么要对synchronized进行优化?

  因为Java虚拟机是通过进入和退出Monitor对象来实现代码块同步和方法同步的,而Monitor是依靠底层操作系统的Mutex Lock来实现的,操作系统实现线程之间的切换需要从用户态转换到内核态,这个切换成本比较高,对性能影响较大。

偏向锁

轻量级锁

重量级锁

标签:Java,Monitor,synchronized,Thread,线程,println,NULL
From: https://www.cnblogs.com/antidogmatist/p/17027418.html

相关文章

  • Java泛型
    Java泛型泛型上下限泛型的上限格式:<?extends类>含义:只能接收该类型及其子类泛型的下限格式:<?super类>含义:只能接收该类型及其父类......
  • java中的多线程
    一.线程的创建线程的创建方式有两种:一种是继承Thread类,重写run()方法【这里的run()方法只是普通的方法】,在主方法中,创建该类的对象,调用对象的start()方法。二种是实现R......
  • java.io.IOException: Permission denied——文件导出时报错
    背景业务系统中,有一个导出,就是很普通的列表查询,然后可以点击导出,生成一个文件。就这么一个功能。使用的excel工具类是:org.apache.poi.xssf用的poi这个工具类。问题......
  • Java基础语法
    基本的dos命令打开cmd的方式开始+系统+命令提示行Win+R输入cmd打开控制台在任意的文件夹下面,按住shift+鼠标右键,在此处打开命令行窗口资源管理器的地址栏前面加上......
  • Java毕业生就业系统学生就业统计系统
    简介本项目主要是为了统计毕业生就业情况(就业方向分为四种:参加工作,考研,自主创业,待就业),教师可登入该系统查看学生就业情况,包括:考研、职业领域、工作城市,薪资等统计情况,并且......
  • Java JUC学习笔记
    1、JUC简介在Java5.0提供了java.util.concurrent(简称JUC)包,在此包中增加了在并发编程中很常用的工具类,用于定义类似于线程的自定义子系统,包括线程池,异步IO和轻量......
  • java在线视频播放系统视频网站影视网站电影电视剧播放网站源码
    简介ssm开发的视频网站。本项目主要包括了视频展示和查询功能,用户中心,积分管理,管理员管理等功能。演示视频https://www.bilibili.com/video/BV1tT4y1N7t8/?share_source......
  • java旅游日志博客系统旅行记录系统
    简介记录个人旅游动态日志的系统,也可以用来做博客系统,主页可以发布旅游日志,关注博主,给博主留言,管理评论,博文点赞,个人主页。演示视频https://www.bilibili.com/video/BV......
  • Java学习笔记
    一、Java8新特性1、HashMap​​深入浅出学Java——HashMap​​​​算法复杂度O(1),O(n),O(logn),O(nlogn)的含义​​2、ConcurrentHashMap​​HashMap?ConcurrentHashMap?相信......
  • Java个人博客系统ssh个人博客系统家乡特产家乡风景
    简介Java基于ssh开发的个人博客系统,主要有家乡特产文章,家乡风景,照片墙,留言等功能演示视频https://www.bilibili.com/video/BV1Yy4y1e7VR/?share_source=copy_web&vd_sou......