简介
同步赋值就是我们最常用的方式
public class Test {
public static void main(String[] args) {
Test test = new Test();
test.setValue("123");
System.out.println(test.getValue());
}
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
其中test对象中的value set 赋值 get取值。这个在单线程中是没问题的。
但是假如说变成多线程呢。
public class Test {
public static void main(String[] args) {
Test test = new Test();
new Thread(() -> {
//1赋值
test.setValue("123");
}).start();
//2获取值
System.out.println(test.getValue());
}
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
这种情况赋值与获取值,就没办法保证先后顺序。获取值的时候有可能另一个线程还没有赋值,或者,已经赋值,但线程间的缓存还不一致。
那线程间的值同步该怎么做?
方案一 synchronized
package com.hcq.async;
/**
* 同步方法一
*/
public class Model1 {
//使用volatile 防止线程缓存
private volatile String value;
public synchronized String getValue() {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
return value;
}
public synchronized void setValue(String value) {
//先赋值,再同步
this.value = value;
this.notify();
}
}
这种方案是最简单的一步方案。
缺点:
- 锁比较重
- 多次赋值有些问题。
- 如果赋值线程在先,会出现死锁问题。
方案二 synchronized+ volatile
public class Model2 {
//使用volatile 防止线程缓存
private volatile String value;
private volatile boolean isOk = false;
public synchronized String getValue() {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
return value;
}
public synchronized void setValue(String value) {
if (this.isOk == true) {
System.out.println("已经赋值[" + this.value + "],赋值【" + value + "]失败!");
} else {
//先赋值,再同步
this.isOk = true;
this.value = value;
System.out.println("赋值[" + this.value+"]");
this.notify();
}
}
}
这种方案解决了多次赋值问题。
- 锁比较重
- 如果赋值线程在先,会出现死锁问题。
方案三 CountDownLatch + Cas
public class Model3 {
//使用volatile 防止线程缓存
private volatile String value;
private AtomicBoolean isOk = new AtomicBoolean(false);
private CountDownLatch lock = new CountDownLatch(1);
public String getValue() {
try {
lock.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
return value;
}
public void setValue(String value) {
//幂等操作
if (isOk.compareAndSet(false, true)) {
//先赋值,再同步
this.value = value;
System.out.println("赋值[" + this.value+"]");
this.lock.countDown();
} else {
System.out.println("已经赋值[" + this.value + "],赋值【" + value + "]失败!");
}
}
}
用AtomicBoolean 来解决重复调用的幂等问题。
用CountDownLatch解决 先赋值死锁问题。
代码: https://github.com/jlhuang9/iptest/tree/master/src/main/java/com/hcq/async