测试程序1:两个线程对同一个变量的可见性问题
static int n = 0;
static void testMultiThreadVisiable(){
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
while(true){
if(n == 1){
System.out.println(System.currentTimeMillis());
break;
}
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("start set." + System.currentTimeMillis());
n = 1;
System.out.println("end set." + System.currentTimeMillis());
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
testMultiThreadVisiable();
}
运行结果
/usr/local/jdk1.8.0_291/bin/java -javaagent:/home/yeqiang/program/idea-IC-192.6603.28/lib/idea_rt.jar=40477:/home/yeqiang/program/idea-IC-192.6603.28/bin -Dfile.encoding=UTF-8 -classpath /usr/local/jdk1.8.0_291/jre/lib/charsets.jar:/usr/local/jdk1.8.0_291/jre/lib/deploy.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/cldrdata.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/dnsns.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/jaccess.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/jfxrt.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/localedata.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/nashorn.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/sunec.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/sunjce_provider.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/sunpkcs11.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/zipfs.jar:/usr/local/jdk1.8.0_291/jre/lib/javaws.jar:/usr/local/jdk1.8.0_291/jre/lib/jce.jar:/usr/local/jdk1.8.0_291/jre/lib/jfr.jar:/usr/local/jdk1.8.0_291/jre/lib/jfxswt.jar:/usr/local/jdk1.8.0_291/jre/lib/jsse.jar:/usr/local/jdk1.8.0_291/jre/lib/management-agent.jar:/usr/local/jdk1.8.0_291/jre/lib/plugin.jar:/usr/local/jdk1.8.0_291/jre/lib/resources.jar:/usr/local/jdk1.8.0_291/jre/lib/rt.jar:/home/yeqiang/code/untitled/out/production/untitled com.company.Main start set.1658303958008 end set.1658303958008
线程t1观测到的n=0,一直处于死循环状态。
测试程序2:采用volatile修饰变量n,即
static volatile int n = 0;
运行结果
/usr/local/jdk1.8.0_291/bin/java -javaagent:/home/yeqiang/program/idea-IC-192.6603.28/lib/idea_rt.jar=34637:/home/yeqiang/program/idea-IC-192.6603.28/bin -Dfile.encoding=UTF-8 -classpath /usr/local/jdk1.8.0_291/jre/lib/charsets.jar:/usr/local/jdk1.8.0_291/jre/lib/deploy.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/cldrdata.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/dnsns.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/jaccess.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/jfxrt.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/localedata.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/nashorn.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/sunec.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/sunjce_provider.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/sunpkcs11.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/zipfs.jar:/usr/local/jdk1.8.0_291/jre/lib/javaws.jar:/usr/local/jdk1.8.0_291/jre/lib/jce.jar:/usr/local/jdk1.8.0_291/jre/lib/jfr.jar:/usr/local/jdk1.8.0_291/jre/lib/jfxswt.jar:/usr/local/jdk1.8.0_291/jre/lib/jsse.jar:/usr/local/jdk1.8.0_291/jre/lib/management-agent.jar:/usr/local/jdk1.8.0_291/jre/lib/plugin.jar:/usr/local/jdk1.8.0_291/jre/lib/resources.jar:/usr/local/jdk1.8.0_291/jre/lib/rt.jar:/home/yeqiang/code/untitled/out/production/untitled com.company.Main start set.1658304324424 end set.1658304324424 1658304324424 Process finished with exit code 0
结果分析:volatile强制变量n线程之前可见,t2设置n=1后,t1立刻退出了循环。
扩展测试1.采用Thread.sleep 让t1休眠一小段时间
static int n = 0;
static void testMultiThreadVisiable(){
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
while(true){
if(n == 1){
System.out.println(System.currentTimeMillis());
break;
}
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("start set." + System.currentTimeMillis());
n = 1;
System.out.println("end set." + System.currentTimeMillis());
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
testMultiThreadVisiable();
}
输出
/usr/local/jdk1.8.0_291/bin/java -javaagent:/home/yeqiang/program/idea-IC-192.6603.28/lib/idea_rt.jar=38567:/home/yeqiang/program/idea-IC-192.6603.28/bin -Dfile.encoding=UTF-8 -classpath /usr/local/jdk1.8.0_291/jre/lib/charsets.jar:/usr/local/jdk1.8.0_291/jre/lib/deploy.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/cldrdata.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/dnsns.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/jaccess.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/jfxrt.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/localedata.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/nashorn.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/sunec.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/sunjce_provider.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/sunpkcs11.jar:/usr/local/jdk1.8.0_291/jre/lib/ext/zipfs.jar:/usr/local/jdk1.8.0_291/jre/lib/javaws.jar:/usr/local/jdk1.8.0_291/jre/lib/jce.jar:/usr/local/jdk1.8.0_291/jre/lib/jfr.jar:/usr/local/jdk1.8.0_291/jre/lib/jfxswt.jar:/usr/local/jdk1.8.0_291/jre/lib/jsse.jar:/usr/local/jdk1.8.0_291/jre/lib/management-agent.jar:/usr/local/jdk1.8.0_291/jre/lib/plugin.jar:/usr/local/jdk1.8.0_291/jre/lib/resources.jar:/usr/local/jdk1.8.0_291/jre/lib/rt.jar:/home/yeqiang/code/untitled/out/production/untitled com.company.Main start set.1658304812227 end set.1658304812227 1658304812228 Process finished with exit code 0
说明:t1线程每个循环都会休眠1毫秒,是CPU空闲,t2线程修改n=1,待t1线程唤醒后,可以得到最新的数据。此时并没有使用volatile修饰变量n,但这是一种低效且不安全的方法。



