JAVA-volatile 코스메틱 참조 유형 변수는 속성의 가시성을 보장합니까?
17289 단어 JAVA 다중 스레드 및 높은 동시 연결
먼저 결론: 안 돼!
volatile는 대상을 수식합니다. 만약 대상의 속성 (구성원 변수) 이 바뀌면volatile는 다른 라인이 이 변화를 관찰할 수 있도록 보장할 수 없습니다.
처음에 나는 일부 문장에서volatile가 인용 유형의 변수를 수식하면 '인용'의 주소 변화 (즉 변수가 다른 대상을 가리키는 것) 는 다른 라인에 대해 볼 수 있지만 인용 대상의 속성 변화는 다른 라인에 대해 볼 수 없다는 것을 보았다.
실사구시의 정신에 따라 나는 몇 가지 예를 썼다. 몇 가지 시도를 통해 일반 대상의 속성의 변화를 발견했고volatile는 그 변화가 볼 수 있다는 것을 보장할 수 있다.
하지만!!!
대량의 테스트를 한 후에 나는 다른 라인이 매번 대상 속성의 변화를 관찰할 수 있는 것이 아니라는 것을 발견했다. 특히 대상의 속성이 여러 번 변화할 때!따라서 결론은volatile는 인용 유형 대상의 속성의 가시성을 확실히 보장할 수 없다는 것이다.
또 하지만!만약에 대상 속성의 라인을 수정하고 슬립을 한 번 하면 1초라도 볼 수 있다. 정말 이상하다. 나중에 시간이 있으면 JVM이나 운영체제의 메모리 관리를 연구해 보면 알 수 없을 것이다.(sleep일 수도 있고, 테스트 횟수가 많지 않을 수도 있다)
다음은 테스트의 예입니다. 만약에 여러 번(10번 정도)을 실행하면volatile 수식의 인용 유형 변수를 볼 수 있습니다. 루틴 t2는 이 인용 유형 대상의 속성을 수정하고 있습니다. 만약에 수정된 루틴 t2(생산자)가sleep가 없다면 t1은 매번 어떤 변화를 관찰할 수 없습니다.
/**
* @author liweizhi
* @date 2020/3/4 18:18
*/
public class VolatileObject {
volatile static Pet pet = new Pet("dahuang", 1);
public static void main(String[] args) {
// ageChange nameChange, t1 ( t2 sleep)
nameChange();
// ageChange();
}
private static void ageChange() {
new Thread(() -> {
System.out.println("t1 start "/* + Instant.now()*/);
while (true) {
if (pet.getAge() == 5) {
break;
}
}
System.out.println("t1 end "/* + Instant.now()*/);
}, "t1").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
Pet myPet = pet;
for (int i = 1; i <= 100; i++) {
int age = myPet.getAge();
myPet.setAge(++age);
/*try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
}
System.out.println("t2 end "/* + Instant.now()*/);
}, "t2").start();
}
private static void nameChange() {
new Thread(() -> {
System.out.println("t1 start "/* + Instant.now()*/);
while (true) {
if ("xiaobai8".equals(pet.getName())) {
break;
}
}
System.out.println("t1 end "/* + Instant.now()*/);
}, "t1").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
Pet myPet = pet;
for (int i = 1; i <= 10; i++) {
myPet.setName("xiaobai" + i);
/*try {
TimeUnit.NANOSECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
}
System.out.println("t2 end "/* + Instant.now()*/);
}, "t2").start();
}
static class Pet {
String name;
int age;
public Pet(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
}