• 【java多线程】synchronized和volatile


    一.synchronized

    1.synchronized使用的方法

    • 可以直接修饰代码块
    synchronized (this) {
    	//代码块
    }
    
    • 调用可能出现并发问题的方法
    synchronized (this) {
    	method();
    }
    
    • 修饰方法
    public synchronized void method() {
    	//...
    }
    

    2.注意

    当synchronized修饰方法时:

    • 非静态方法中,synchronized锁当前对象:this
    • 静态方法中,synchronized锁的是当前类的字节码对象User.class

    3.不要以字符串作为锁的对象

    • 有如下代码
    String s1 = "hello";
    String s2 = "hello";
    
    void m1() {
        synchronized (s1) {
        }
    }
    void m2() {
        synchronized (s2) {
        }
    }
    
    • 因为s1s2的创建都使用的是直接赋值,此时的hello会创建在常量池中,实际上s1s2都指向的是同一个对象,被s1、s2引用。
    • 所以,此时的synchronized (s1)synchronized (s2)实际上锁的都是同一个对象。
    • 因此,使用synchronized锁的时候最好不要锁字符串类型。
    • 如果非要锁字符串,那么使用new String ("hello")的方法来创建字符串,因为这样创建出来的字符串就是两个堆内存中的对象了。

    4.synchronized锁的是什么?

    • synchronized锁的是堆内存中new出来的对象,而不是栈中的引用。
      在这里插入图片描述

    二、volatile

    1.引出问题

    在这里插入图片描述

    两个线程操作同一个主存数据时,会先将主存中的数据复制到自己的内存区域,将数据修改后,再写回主存。


    两线程同时复制到自己内存后:

    • 线程1将数据修改a=1后,写回主存
    • main线程很忙,一直在进行while(true) 循环,没有时间再去主存中读取新的数据,所以main线程缓存中的数据还是a=0
    • 为了解决这个问题,就引出了volatile

    2. volatile使用方法

    • 直接将volatile关键字加在要操作的数据上
    private volatile int a = 0;
    

    3.volatile原理

    • 线程1将数据修改后,会通知main线程:“你的数据已经过期了”
    • 此时main线程会从主存中重新读取新的数据
    • 这也就是volatile三个特性的-保证可见性
      在这里插入图片描述

    4.volatile三大特性

    • 保证可见性
    • 不保证原子性
    • 禁止指令重排

    三、volatile和synchronized的区别

    1.区别

    • volatile是轻量级的,synchronized是是重量级的
    • volatile保证内存可见性,而不保证原子性(解决此问题的办法:就是使用原子数据)
    • synchronized既保证内存可见性,也保证原子性

    2.解决原子性问题–原子型数据类型

    • java.util.concurrent.atomic包下,有基本数据类型对应的原子型的数据类型,类似于基本数据类型的包装类型。
      在这里插入图片描述

    3.让对象类型数据具有原子型

    • 还是在java.util.concurrent.atomic包下,有一个类,可以使对象类型的数据具有原子性:AtomicReference
    //创建两个对象
    User zhangsan = new User("zhangsan");        
    User sili = new User("sili");
    //创建原子操作对象
    AtomicReference<User> atomicReference = new AtomicReference<User>();
    //比较并交换
    boolean b = atomicReference.compareAndSet(zhangsan, sili);
    System.out.println(b);
    
    为天地立心,为生民立命,为往圣继绝学,为万世开太平。
  • 相关阅读:
    Nginx与Apache的对比
    gc buffer busy waits(ZT)
    Brocade SAN Switch Change Domain ID (ZT)
    Oracle异机恢复时报错ora19870 ora19507
    row cache lock (ZT)
    can a select block a truncate (ZT)
    NBU常用命令
    the RRD does not contain an RRA matching the chosen C
    Solaris10 x64安装64bit perl
    Solaris and Oracle 32bit Linking Error "fatal: symbol 'ntcontab'
  • 原文地址:https://www.cnblogs.com/rxx1005/p/12527243.html
Copyright © 2020-2023  润新知