Synchronized关键字研究

实现原理

synchronized采用的是锁机制,java中每个对象都有一个锁,在同一时刻,只有一个线程可以获得该锁,其他线程想要获取该锁的话,必须等到已经获取该锁的线程释放锁之后,因此synchronized正是通过获取对象的锁来保证不同线程的同步。

  • synchronized可以获取两种对象的锁:

    • 实例对象的锁:即java类的实例
    • 类的class对象
    
    public class B {
    
        public void method(){
    
            synchronized (this){
                //获取类的实例的锁
            }
            synchronized (B.class){
                //获取类的calss对象的锁
            }
    
        }
    
    }
  • synchronized可以修饰的位置

    • 修饰静态方法,获取的是类的class对象的锁
    • 修饰非静态方法,获取的是类的实例的锁
    • 修饰代码块,这时候可以获取上述的两种锁,要视具体情况,如果作用于instance,那么获取的就是类的实例的锁,如果作用于class对象,那么获取的就是类的class对象的锁
    public class B {
    
        public void method(){
            /*
                修饰代码块
             */
    
            synchronized (this){
                //获取类的实例的锁
            }
            synchronized (B.class){
                //获取类的calss对象的锁
            }
    
        }
        /*
            修饰静态方法,获取的是类的class对象的锁
         */
        public synchronized static void staticOutput(){
    
        }
    
        /*
            修饰非静态方法,获取的是类的实例的锁
         */
        public synchronized  void output(){
    
        }
    
    }

详细介绍

获取instance锁

当synchronized获取instance锁时

/*
        修饰非静态方法,获取的是类的实例的锁
     */
    public synchronized  void output(){

    }

    /*
        修饰非静态方法,获取的是类的实例的锁
     */
    public synchronized  void intput(){

    }
    public void method(){
        /*
            修饰代码块
         */

        synchronized (this){
            //获取类的实例的锁
            //C代码块
        }
        synchronized (B.class){
            //获取类的calss对象的锁
            //D代码块
        }

    }
  • 如果是相同的实例,那么多个线程同时只能有一个线程执行synchronized修饰的方法或者代码块,并且如果线程1此时正在执行output(),那么线程2是不能够同时执行input(),也不能同时执行method()的C代码块,因为这时候synchronized获取的是这个instance的锁(唯一)
  • 如果是相同的实例,如果线程1此时正在执行output(),那么线程2可以执行非synchronized修饰的方法或者代码块
  • 如果不是相同的实例,那么在不同线程执行到synchronized时,是没有影响的,即只要这两个线程的instance不同,那么线程1和线程2可以同时执行output() intput() 以及C代码块

也就是说synchronized的机制主要跟获取的哪个对象的锁有关,跟修饰的位置没有关系,对象不一致,那么获取的锁就不一致,那么也就没法保证不同线程的同步

获取类class锁

当synchronized修饰static方法或者后跟XXX.class时,表示执行修饰位置的代码需要获取类的class对象锁

    public void method(){
        /*
            修饰代码块
         */

        synchronized (this){
            //获取类的实例的锁
            //C代码块
        }
        synchronized (B.class){
            //获取类的calss对象的锁
            //D代码块
        }

    }
    /*
        修饰静态方法,获取的是类的class对象的锁
     */
    public synchronized static void staticOutput(){

    }
  • 同一时刻,只有一个线程能执行synchnized修饰的方法,线程1和线程2不能同时执行staticOutPut(),不管调用方式,B.staticOutput()B b = new B();b.staticOutput()一样不可以同时执行,因为要调用staticOutPut()需要获取B.class的锁
  • 同一时刻,线程1执行staticOutPut()时,线程2不会执行上述代码中的D代码块,因为获取的都是同一个B.class的锁

synchronized能否保证原子性可见性有序性

原子性

因为synchronized使用的互斥锁机制,因此,它能够保证synchronized修饰的代码块的的操作是原子性的,也就是说他能保证在修饰位置代码执行过程中,其他线程想要执行这段代码的话,都必须等待线程1释放锁

可见性

在线程1执行到C代码块时之前的synchronized代码块时,会拷贝一份i的副本,同时线程2这时候也执行到这里时,也会拷贝副本,但是会阻塞,当线程1执行完时,由于synchronized保证了可见性,所以在线程执行完+1操作后,线程2会知道i的值在主内存中已经变化,会重新从主存中取i的值然后进行操作,也就是说线程2能知道线程1执行完后的操作结果

    int i = 1;
    public void method(){
        /*
            修饰代码块
         */

        synchronized (this){
            //获取类的实例的锁
            //C代码块
            i++;
            System.out.println("i="+i);
        }
        /*synchronized (B.class){
            //获取类的calss对象的锁
            //D代码块
        }*/

    }

有序性

synchronized不能保证有序性,要保证有序性,配合valotile关键字

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值