今天工作时,我在Java中遇到了volatile关键字。不是很熟悉,我找到了这个解释。
鉴于那篇文章详细解释了所讨论的关键字,您曾经使用过它吗?或者您曾经看到过以正确方式使用该关键字的情况吗?
今天工作时,我在Java中遇到了volatile关键字。不是很熟悉,我找到了这个解释。
鉴于那篇文章详细解释了所讨论的关键字,您曾经使用过它吗?或者您曾经看到过以正确方式使用该关键字的情况吗?
当前回答
使用volatile的一个常见示例是使用volatile布尔变量作为终止线程的标志。如果您已经启动了一个线程,并且希望能够安全地从另一个线程中断它,您可以让线程定期检查标志。要阻止它,将标志设置为true。通过将标志设置为易失性,可以确保正在检查它的线程在下次检查时看到它已经设置好,甚至不必使用同步块。
其他回答
Volatile对于停止线程非常有用。
并不是说您应该编写自己的线程,Java 1.6有很多不错的线程池。但是如果你确定你需要一个线程,你需要知道如何停止它。
我使用的线程模式是:
public class Foo extends Thread {
private volatile boolean close = false;
public void run() {
while(!close) {
// do work
}
}
public void close() {
close = true;
// interrupt here if needed
}
}
在上面的代码段中,while循环中读取close的线程与调用close()的线程不同。如果没有volatile,运行循环的线程可能永远看不到关闭的更改。
注意,这里不需要同步
是的,我经常使用它——它对多线程代码非常有用。你指的那篇文章很好。不过有两件重要的事情要记住:
You should only use volatile if you completely understand what it does and how it differs to synchronized. In many situations volatile appears, on the surface, to be a simpler more performant alternative to synchronized, when often a better understanding of volatile would make clear that synchronized is the only option that would work. volatile doesn't actually work in a lot of older JVMs, although synchronized does. I remember seeing a document that referenced the various levels of support in different JVMs but unfortunately I can't find it now. Definitely look into it if you're using Java pre 1.5 or if you don't have control over the JVMs that your program will be running on.
假设一个线程修改了一个共享变量的值,如果你没有对该变量使用volatile修饰符的话。当其他线程想要读取这个变量的值时,它们看不到更新后的值,因为它们是从CPU的缓存而不是RAM内存中读取变量的值。这个问题也被称为能见度问题。
通过将共享变量声明为volatile,所有对计数器变量的写入都将立即写入主存。同样,所有对counter变量的读取都将直接从主存中读取。
public class SharedObject {
public volatile int sharedVariable = 0;
}
对于非易失性变量,不能保证Java虚拟机(JVM)何时将数据从主存读取到CPU缓存,或何时将数据从CPU缓存写入主存。这可能会导致几个问题,我将在下面的部分中解释这些问题。
例子:
想象这样一种情况,两个或多个线程可以访问一个共享对象,该对象包含一个声明如下的计数器变量:
public class SharedObject {
public int counter = 0;
}
再想象一下,只有线程1增加计数器变量,但是线程1和线程2都可以不时地读取计数器变量。
如果计数器变量没有被声明为volatile,则不能保证计数器变量的值何时从CPU缓存写入主存。这意味着CPU缓存中的计数器变量值可能与主存中的不相同。这种情况如下所示:
线程看不到一个变量的最新值,因为它还没有被另一个线程写回主存,这个问题被称为“可见性”问题。一个线程的更新对其他线程是不可见的。
如果您正在开发多线程应用程序,您将需要使用'volatile'关键字或'synchronized'以及您可能拥有的任何其他并发控制工具和技术。桌面应用就是这样一个例子。
If you are developing an application that would be deployed to application server (Tomcat, JBoss AS, Glassfish, etc) you don't have to handle concurrency control yourself as it already addressed by the application server. In fact, if I remembered correctly the Java EE standard prohibit any concurrency control in servlets and EJBs, since it is part of the 'infrastructure' layer which you supposed to be freed from handling it. You only do concurrency control in such app if you're implementing singleton objects. This even already addressed if you knit your components using frameworkd like Spring.
因此,在Java开发的大多数情况下,应用程序是一个web应用程序,并使用IoC框架,如Spring或EJB,你不需要使用'volatile'。
Volatile执行以下操作。
不同线程对volatile变量的读写总是从内存,而不是从线程自己的缓存或cpu寄存器。所以每个线程总是处理最新的值。 2>当两个不同的线程在堆中使用相同的实例或静态变量时,其中一个线程可能会认为其他线程的操作是无序的。请看jeremy manson的博客。但不稳定在这里有所帮助。
下面完全运行的代码展示了如何在不使用synchronized关键字的情况下以预定义的顺序执行多个线程并打印输出。
thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3
thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3
thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3
为了实现这一点,我们可以使用以下完整的运行代码。
public class Solution {
static volatile int counter = 0;
static int print = 0;
public static void main(String[] args) {
// TODO Auto-generated method stub
Thread[] ths = new Thread[4];
for (int i = 0; i < ths.length; i++) {
ths[i] = new Thread(new MyRunnable(i, ths.length));
ths[i].start();
}
}
static class MyRunnable implements Runnable {
final int thID;
final int total;
public MyRunnable(int id, int total) {
thID = id;
this.total = total;
}
@Override
public void run() {
// TODO Auto-generated method stub
while (true) {
if (thID == counter) {
System.out.println("thread " + thID + " prints " + print);
print++;
if (print == total)
print = 0;
counter++;
if (counter == total)
counter = 0;
} else {
try {
Thread.sleep(30);
} catch (InterruptedException e) {
// log it
}
}
}
}
}
}
下面的github链接有一个自述,它给出了适当的解释。 https://github.com/sankar4git/volatile_thread_ordering