包含标签 并发 的文章

Atomic

Atomic 是指一个操作是不可中断的。即使是在多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程干扰。 所以,所谓原子类说简单点就是具有原子/原子操作特征的类 public final int get() //获取当前的值 public final int getAndSet(int newValue)//获取当前的值,并设置新的值 public final int getAndIncrement()//获取当前的值,并自增 public final int getAndDecrement() //获取当前的值,并自减 public final int getAndAdd(int delta) //获取当前的值,并加上预期的值 boolean compareAndSet(int expect, int update) //如果输入的数值等于预期值,则以原子方式将该值设置为输入值(update) public final void lazySet(int newValue)//最终设置为newValue,使用 lazySet 设置之后可能导致其他线程在之后的一小段时间内还是可以读到旧的值。 基本数据类型原子类优势 - ①多线程环境不使用原子类保证线程安全(基本数据类型) class Test { private volatile int count = 0; //若要线程安全执行执行count++,需要加锁 public synchronized void increment() { count++; } public int getCount() { return count; } } ②多线程环境使用原子类保证线程安全……

阅读全文

Volatile

并发编程3个重要特性 并发编程的三个重要特性原子性、可见性、有序性 原子性 即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。 可见性 可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。 有序性 即程序执行的顺序按照代码的先后顺序执行。 >java int a = 10; int b = 5; > 在Java内存模型中,允许编译器和处理器对指令进行重排序,但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。 ps:要想并发程序正确地执行,必须要保证原子性、可见性以及有序性。只要有一个没有被保证,就有可能会导致程序运行不正确。 volatile volatile语义 - 1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。(保证变量的可见性) - 2)禁止进行指令重排序。(保证有序性) 为什么不保证原子性:volatile修饰的属性若再修改前被另一个线程读取了值,那么修改后,无法改变已经复制到工作内存中的值。 volatile static int a=0; a++; // 包含了2步操作:1、读取a。2、执行a+1 & 将a+1结果赋值给a // 设:线程A、B同时执行以下语句,线程A执行完第1步后被挂起、线程B执行了a++,那么主存中a的值为1 // 但线程A的工作内存中还是0,由于线程A之前已读取了a的值 = 0,执行a++后再次将a的值刷新到主存 = 1 // 即 a++执行了2次,但2次都是从0变为1,故a的值最终为1 通过上图可知: Java内存模型规定所有的变量都是存在主存当中,每个线程都有自己的工作内存。线程对变量的所有操作都必须在自己的工作内存中进行,而不能直接对主存进行操作。并且每个线程不能访问其他线程的工作内存。 Java内存模型只保证了基本读取和赋值是原子性操作。 为什么保证可见性: - volatile修饰的属性能够保证每次读取都是最新的值 - 但在多线程下不会也无法更新已经读取了的值 (1)对于普通的成员变量不能保证可见性,因为普通共享变量被修改之后,什么时候被写入主存是不确定的,当其他线程去读取时,此时内存中可能还是原来的旧值,因此无法保证可见性。 (2)当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。 为什么保证有序性重排序时,以volatile修饰的属性的读/写操作代码为分界线(lock前缀指令),读/写操作前的代码不允许排到后面,后面不允许排到前面,由此保证有序性。 使用条件: 您只能在有限的一些情形下使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件: - 对变量的写操作不依赖于当前值。 - 该变量没有包含在具有其他变量的不变式中。……

阅读全文