volatile 修饰的变量,可以使线程每次从共享内存中读取变量。 解决了可见性问题但是解决不了原子性问题。下来我们分别验证:
一、验证可见性
1.flag没有被volatile 修饰
public class TestVolate2
{
// 没有被volatile修饰
private boolean flag = true;
// 停止线程
void stop(boolean flag) throws InterruptedException
{
this.flag = flag;
System.out.println(Thread.currentThread().getName() + "false");
}
// 死循环
void doWork()
{
while (flag)
{
}
System.out.println(Thread.currentThread().getName() + "停止了");
}
public static void main(String[] args) throws InterruptedException
{
TestVolate2 t = new TestVolate2();
// 启动10个线程
for (int i = 0; i < 10; i++)
{
new Thread()
{
@Override
public void run()
{
t.doWork();
}
}.start();
}
Thread.sleep(1000);
// 停止线程
t.stop(false);
}
}
输出:
2、flag被volatile 修饰,输出
结论:volatile 修饰的变量,可以使线程每次从公享内存中读取变量。
二、volatile 非原子性验证
1.count被volatile 修饰,验证是否线程安全。
public class TestVolate
{
// count 被volate 修饰,解决了可见性,但是解决不了原子性。
public static volatile int count = 0;
// addcount
static void addCount()
{
for(int i = 0; i < 1000; i++)
{
count++;
}
System.out.println(count);
}
// 主函数
public static void main(String[] args)
{
// 启动10个线程
for (int i = 0; i < 10; i++)
{
new Thread(new Runnable()
{
@Override
public void run()
{
TestVolate.addCount();
}
}).start();
}
}
}
输出:
结论2:我们的预期结果是有一个线程会输出10_000;从结果来看,远远不到10_000。这种问题的根因在于count++非原子操作。
volatile 虽然解决了可见性问题,但是解决不了原子性。故出现线程安全问题。解决这个问题,可借助锁机制。
使用synchronized解决线程安全问题