线程安全问题与volatile字段

线程安全问题

/**
 * 出现有些没加入list的缘由:线程一拿走了这个list当时里面有10个数据,添加一个变成11个
 * 线程二同时拿走了这个list,当时里面有10个数据,添加一个变成11个(可是正常应该是12个,也就是线程1添加的那个数据没有了)
 */
public class Ticket implements Runnable{
    
    private List<String> list = new ArrayList<>();

    public void run(){
        for(int i=0;i<300;i++){
            try {
                // 调用Thread类的sleep方法,休眠50ms,因为父接口没有throws异常,so咱们只能用try...catch
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            list.add("xxx,");
            System.out.println(list.size());
        }
    }

}

结论:多线程操做同一个全局变量,加上线程锁吧java

volatile字段

volatile字段的做用:往常线程都是将某个变量复制一份到本身的线程中,通过volatile字段修饰后,就统一的从内存中读取安全

原理:volatile本质是在告诉jvm当前变量在寄存器(工做内存)中的值是不肯定的,须要从主存中读取;多线程

Volatile 变量具备 synchronized 的可见性特性,可是不具有原子性。这就是说线程可以自动发现 volatile 变量的最新值。jvm

  •  volatile 变量不能用做线程安全计数器。虽然增量操做(x++)看上去相似一个单独操做,实际上它是一个由(读取-修改-写入)操做序列组成的组合操做,必须以原子方式执行,而 volatile 不能提供必须的原子特性。

用处:若是读操做远远大于写操做,volatile 变量还能够提供优于锁的性能优点。性能

两个字段的区别

  1. volatile本质是在告诉jvm当前变量在寄存器(工做内存)中的值是不肯定的,须要从主存中读取; synchronized则是锁定当前变量,只有当前线程能够访问该变量,其余线程被阻塞住
  2. volatile仅能使用在变量级别;synchronized则可使用在变量、方法、和类级别的
  3. volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则能够保证变量的修改可见性和原子性
  4. volatile不会形成线程的阻塞;synchronized可能会形成线程的阻塞。
  5. volatile标记的变量不会被编译器优化;synchronized标记的变量能够被编译器优化
相关文章
相关标签/搜索