编写正确的程序很难,而编写正确的并发程序则难上加难。与串行程序相比,在并发程序中存在更多容易出错的地方。那么,为何我们还要使用并发程序?线程是Java语言中不可或缺的重要功能,它们能使复杂的异步代码变得简单,从而极大地简化了复杂系统的开发。
线程只能操作自己工作空间中的数据
每个工作线程都有自己的工作内存,所以当某个线程修改完某个变量之后,在其他的线程中,未必能观察到该变量已经被修改。
如何保证可见性?
一、 使用 volatile
关键字
1、 volatile关键字要求被修改之后的变量要求立即更新到主内存,每次使用前从主内存处进行读取。
2、当修饰引用类型的时候, 只能保证引用本身的可见性, 不能保证内部字段的可见性
二、 使用 synchronized加锁
1、synchronization
它会保证unlock之前必须先将变量重新刷入主内存当中。
从而达到多个线程确保从主内存当中拿到的数据一致
一、 原子性就是指对数据的操作是一个独立的、不可分割的整体。换句话说,就是一次操作,是一个连续不可中断的过程,数据不会执行的一半的时候被其他线程所修改。
二、 示例
X = 5
是一个写操作
具有原子性
Y = X
不具有原子性
先把数据X读取工作空间
再把X值写给Y
是一个读写操作, 不具有原子性
i++
不具有原子性
读i到工作空间
+1后写到给i
刷新结果到内存
a = a + 1
不具有原子性
读a到工作空间
+1
刷新结果到内存
三、如何保证原子性
1. Synchronized
2. JUC Lock加锁
被synchronized关键字或其他锁包裹起来的操作也可以认为是原子的。从一个线程观察另外一个线程的时候,看到的都是一个个原子性的操作
。