三大性质
原子性
原子性是指一个操作是不可中断的,要么全部执行成功要么全部执行失败
由原子性变量操作read,load,use,assign,store,write,
可以大致认为基本数据类型的访问读写具备原子性(例外就是long和double的非原子性协定)
synchronized满足原子性;
volatile并不能保证原子性;
如果让volatile保证原子性,必须符合以下两条规则:
1)运算结果并不依赖于变量的当前值,或者能够确保只有一个线程修改变量的值;
2)变量不需要与其他的状态变量共同参与不变约束
有序性
synchronized具有有序性;
volatile包含禁止指令重排序的语义,其具有有序性;
java程序天然的有序性可以总结为:如果在本线程内观察,所有的操作都是有序的;如果在一个线程观察另一个线程,所有的操作都是无序的。
可见性
可见性是指当一个线程修改了共享变量后,其他线程能够立即得知这个修改。通过之前对synchronized内存语义进行了分析,当线程获取锁时会从主内存中获取共享变量的最新值,释放锁的时候会将共享变量同步到主内存中。从而,synchronized具有可见性。同样的在volatile分析中,会通过在指令中添加lock指令,以实现内存可见性。因此, volatile具有可见性
相关链接:https://www.jianshu.com/p/cf57726e77f2
public class ThreadV extends Thread{
volatile public static int count;
synchronized private static void addCount() {
for (int i = 0; i < 100; i++) {
count++;
}
System.out.println("count = " + count);
}
public void run() {
addCount();
}
}
public class RunV {
public static void main(String[] args) {
ThreadV[] tarr = new ThreadV[100];
for(int i = 0; i < 100; i++) {
tarr[i] = new ThreadV();
}
for(int i = 0; i < 100; i++) {
tarr[i].start();
}
}
}
使用原子类进行i++操作:
import java.util.concurrent.atomic.AtomicInteger;
public class AddCountThread extends Thread{
private AtomicInteger count = new AtomicInteger(0);
public void run() {
for (int i = 0; i < 10000; i++) {
System.out.println(count.incrementAndGet());
}
}
}
public class RunAddCount {
public static void main(String[] args) {
AddCountThread countService = new AddCountThread();
Thread t1 = new Thread(countService);
t1.start();
Thread t2 = new Thread(countService);
t2.start();
Thread t3 = new Thread(countService);
t3.start();
Thread t4 = new Thread(countService);
t4.start();
Thread t5 = new Thread(countService);
t5.start();
}
}
原子类也并不完全安全
import java.util.concurrent.atomic.AtomicLong;
public class Service {
public static AtomicLong aiRef = new AtomicLong();
synchronized public void addNum() {
System.out.println(Thread.currentThread().getName()
+ "加了100之后的值是:" + aiRef.addAndGet(100));
aiRef.addAndGet(1);
}
}
public class ThreadS extends Thread{
private Service service;
public ThreadS(Service service) {
super();
this.service = service;
}
public void run() {
service.addNum();
}
}
public class RunS {
public static void main(String[] args) {
try {
Service service = new Service();
ThreadS[] array = new ThreadS[5];
for (int i = 0; i < array.length; i++) {
array[i] = new ThreadS(service);
}
for (int i = 0; i < array.length; i++) {
array[i].start();
}
Thread.sleep(1000);
System.out.println(service.aiRef.get());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
synchronized代码块具有volatile同步的功能
总之:synchronized: 具有原子性,有序性和可见性;
volatile:具有有序性和可见性
关键字synchronized可以保证在同一时刻,只有一个线程可以执行某一个方法或者某一个代码块。它包含两个特征:互斥性和可见性。同步synchronized不仅可以解决一个线程看到对象处于不一致的状态,还可以保证进入同步方法或者同步代码块的每个线程,都看到由同一个锁保护之前所有的修改效果。
学习完多线程同步之后就可以有效控制线程间处理数据的顺序性,及对处理后的数据进行有效值的保证,更好地对线程执行结果有正确的预期。