• synchronized的原理与使用


    理论层面:

    内置锁与互斥锁

     修饰普通方法、修饰静态方法、修饰代码块

    demo如下:

    package com.roocon.thread.t3;
    
    public class Sequence {
        private static int value;
    
        // synchronized放在普通方法上,内置锁就是当前方法的实例
        public synchronized int getNext(){
            return value++;
        }
    
        // synchronized修饰静态方法,内置锁就是当前的Class字节码对象Sequence.class
        public static synchronized int getPrevious(){
            return value--;
        }
    
        public int xx(){
            // synchronized修饰静态代码块,则锁的是任意一个对象
            /*
            synchronized (this){ }
            synchronized (Integer.valueOf(value)) { }
            synchronized (Sequence.class) { }
             */
            synchronized (Sequence.class) {
                if (value > 0) {
                    return value;
                }else {
                    return -1;
                }
            }
        }
        public static void main(String[] args) {
            Sequence sequence = new Sequence();
            new Thread(new Runnable() {
                @Override
                public void run() {
                   while (true){
                       System.out.println(Thread.currentThread().getName()+" "+sequence.getNext());
                       try {
                           Thread.sleep(100);
                       } catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                   }
                }
            }).start();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true){
                        System.out.println(Thread.currentThread().getName()+" "+sequence.getNext());
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true){
                        System.out.println(Thread.currentThread().getName()+" "+sequence.getNext());
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }
    }

    jvm层面:

    查看xx方法同步代码块字节码:

    查看同步方法字节码:

    任何对象都可以作为锁,那么锁信息又存在对象的什么地方呢?

    存在对象头中。

    对象头中的信息:

      Mark Word

      Class Metadata Address 类的类型地址

      Array Length

    1.偏向锁:

    每次获得锁和释放锁会浪费资源(消耗时间),很多情况下,竞争锁不是由多个线程,而是由一个线程在使用。线程在获取锁时,会依据对象头Mark word信息进行判断执行。

    对象头Mark word中会保存如下信息:

      线程id

      Epoch

      对象的分代年龄信息

      是否是偏向锁

      锁标志位

    偏向锁在获取锁之后,如果没有竞争,也就是一直是这个线程在获取锁,那么当这个线程第二次再来进入该方法时,不需要再去获取锁了,也不需要释放锁,这样,就节省了大量的获取锁释放锁的资源。那么,什么时候会释放锁呢?只有当存在竞争时,才会去释放锁。

    偏向锁适用于什么场景?

    只有一个线程在访问同步代码块的场景。

    2.轻量级锁:可以同时让多个线程进入同步代码块。自旋锁就是轻量级锁。

    轻量级锁是如何加锁的?

    在线程执行同步代码块之前,jvm会先在当前线程的栈帧中创建用于存储锁记录的存储空间。

    (栈帧是什么?虚拟机栈中存储的是一个一个的栈帧,栈帧中存储了方法的执行信息,每个方法都会伴随着栈帧的进栈和出栈)

    然后呢,并将对象头中的mark word复制到锁记录中。然后呢,开始竞争锁就可以了。竞争成功之后,markword就改变了,会将锁标志位改成轻量级锁。接着,开始执行同步体。

    另外一个线程也想获得该锁。同样,它也将对象头中的mark word复制到锁记录中,它发现已经被其他线程获得了锁,所以它修改不成功。于是,它就不停的去修改,不停的失败,直到第一个线程把这个锁释放了,它就可以修改成功了。刚才这一个过程,就是所谓的自旋锁。

    3.重量级锁

    什么是重量级锁?就是,这个线程获得锁进入之后,其他线程必须在外面等待。synchronized就是重量级锁。

  • 相关阅读:
    mysql 性能优化方案 (转)
    MYSQL 优化常用方法
    php高级研发或架构师必了解---很多问题面试中常问到!
    MetaMask/metamask-extension/mascara 的运行实现
    简单使用metamascara
    nodejs stream 手册学习
    nodejs-stream部分
    metamask中的import account的代码实现
    Signature Request Warnings & eth_sign学习
    gulp学习-metamask前端使用
  • 原文地址:https://www.cnblogs.com/sunnyDream/p/8127595.html
Copyright © 2020-2023  润新知