Java volatile关键字的用途是什么?
在今天的工作中,我遇到了Java中的Java volatile关键字的用途是什么?,java,multithreading,keyword,volatile,Java,Multithreading,Keyword,Volatile,在今天的工作中,我遇到了Java中的volatile关键字。我不太熟悉它,我发现 鉴于那篇文章详细解释了该关键字,您是否曾经使用过它,或者您是否曾经看到过可以正确使用该关键字的情况?“…volatile修饰符保证任何读取字段的线程都会看到最近写入的值。”-Josh Bloch 如果您正在考虑使用volatile,请仔细阅读有关原子行为的软件包。 维基百科上的帖子显示了volatile正在使用中。当然,是的。(不仅在Java中,而且在C#中)有时您需要获取或设置一个值,该值保证在给定平台上是原子操
volatile
关键字。我不太熟悉它,我发现
鉴于那篇文章详细解释了该关键字,您是否曾经使用过它,或者您是否曾经看到过可以正确使用该关键字的情况?“…volatile修饰符保证任何读取字段的线程都会看到最近写入的值。”-Josh Bloch如果您正在考虑使用volatile,请仔细阅读有关原子行为的软件包。
维基百科上的帖子显示了volatile正在使用中。当然,是的。(不仅在Java中,而且在C#中)有时您需要获取或设置一个值,该值保证在给定平台上是原子操作,例如int或boolean,但不需要线程锁定的开销。volatile关键字允许您确保在读取值时获得的是当前值,而不是刚被另一个线程写入而过时的缓存值。
volatile
具有内存可见性的语义。基本上,volatile
字段的值在写入操作完成后对所有读卡器(特别是其他线程)都可见。如果没有volatile,读者可以看到一些未更新的值
回答您的问题:是的,我使用volatile
变量来控制某些代码是否继续循环。循环测试volatile
值,如果为true
则继续。通过调用“停止”方法,可以将条件设置为false
。循环看到false
,并在stop方法完成执行后测试值时终止
我极力推荐的书“,”很好地解释了volatile
。这本书是由同一个人写的,他写了问题中引用的IBM文章(事实上,他在文章的底部引用了他的书)。我使用的volatile
就是他的文章所称的“模式1状态标志”
如果你想了解更多关于引擎盖下的工作原理,请阅读。如果您想超越这一级别,请查阅一本优秀的计算机体系结构书籍,如,并阅读有关缓存一致性和缓存一致性的内容。使用
volatile
的一个常见示例是使用volatile boolean
变量作为终止线程的标志。如果您已经启动了一个线程,并且希望能够安全地从另一个线程中断它,那么可以让该线程定期检查一个标志。要停止,请将标志设置为true。通过设置标志volatile
,您可以确保正在检查它的线程在下次检查它时会看到它已被设置,而无需使用synchronized
块。是的,只要您希望多个线程访问可变变量,就必须使用volatile。这不是很常见的用例,因为通常您需要执行多个原子操作(例如,在修改变量之前检查变量状态),在这种情况下,您将使用同步块。您需要使用“volatile”关键字,或者“synchronized”和任何其他并发控制工具和技术,如果您正在开发多线程应用程序,您可以使用这些工具和技术。桌面应用程序就是这样一个例子
如果您正在开发一个将部署到应用服务器(Tomcat、JBoss AS、Glassfish等)的应用程序,那么您不必自己处理并发控制,因为它已经由应用服务器处理。事实上,如果我没记错的话,javaee标准禁止servlet和ejb中的任何并发控制,因为它是“基础结构”层的一部分,您应该不必处理它。只有在实现单例对象的情况下,才能在此类应用程序中执行并发控制。如果您使用Framework(如Spring)编织组件,甚至已经解决了这一问题
因此,在Java开发的大多数情况下,应用程序是一个web应用程序,并且使用诸如Spring或EJB之类的IoC框架,您不需要使用“volatile”。是的,我经常使用它-它对于多线程代码非常有用。你指的那篇文章很好。尽管有两件重要的事情需要记住:
volatile
对于停止线程非常有用
并不是说您应该编写自己的线程,Java1.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,运行循环的线程可能永远看不到关闭的更改
请注意,不需要同步
volatile
只保证所有线程,甚至线程本身都在递增。例如:计数器同时看到变量的同一面。它不是用来代替同步或原子或其他东西,它完全使读取同步。
package io.netty.example.telnet;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static volatile int a = 0;
public static void main(String args[]) throws InterruptedException{
List<Thread> list = new ArrayList<Thread>();
for(int i = 0 ; i<11 ;i++){
list.add(new Pojo());
}
for (Thread thread : list) {
thread.start();
}
Thread.sleep(20000);
System.out.println(a);
}
}
class Pojo extends Thread{
int a = 10001;
public void run() {
while(a-->0){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
Main.a++;
System.out.println("a = "+Main.a);
}
}
}
package io.netty.example.telnet;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class Main {
public static volatile AtomicInteger a = new AtomicInteger(0);
public static void main(String args[]) throws InterruptedException{
List<Thread> list = new ArrayList<Thread>();
for(int i = 0 ; i<11 ;i++){
list.add(new Pojo());
}
for (Thread thread : list) {
thread.start();
}
Thread.sleep(20000);
System.out.println(a.get());
}
}
class Pojo extends Thread{
int a = 10001;
public void run() {
while(a-->0){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
Main.a.incrementAndGet();
System.out.println("a = "+Main.a);
}
}
}
public class Singleton {
private static volatile Singleton _instance; // volatile variable
public static Singleton getInstance() {
if (_instance == null) {
synchronized (Singleton.class) {
if (_instance == null)
_instance = new Singleton();
}
}
return _instance;
}
}
public class Singleton{
private static Singleton _instance; //without volatile variable
public static Singleton getInstance(){
if(_instance == null){
synchronized(Singleton.class){
if(_instance == null) _instance = new Singleton();
}
}
return _instance;
}
while (busy) {
/* do something else */
}
busy = 0;
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
}
}
}
}
}
}
Stopping on: 1895303906650500
Stopping on: 1895285647980000
324565439> Stopped on: 1895285648087300
Read is after write
public class VisibilityDemonstration {
private static int sCount = 0;
public static void main(String[] args) {
new Consumer().start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
return;
}
new Producer().start();
}
static class Consumer extends Thread {
@Override
public void run() {
int localValue = -1;
while (true) {
if (localValue != sCount) {
System.out.println("Consumer: detected count change " + sCount);
localValue = sCount;
}
if (sCount >= 5) {
break;
}
}
System.out.println("Consumer: terminating");
}
}
static class Producer extends Thread {
@Override
public void run() {
while (sCount < 5) {
int localValue = sCount;
localValue++;
System.out.println("Producer: incrementing count to " + localValue);
sCount = localValue;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
return;
}
}
System.out.println("Producer: terminating");
}
}
}
Consumer: detected count change 0
Producer: incrementing count to 1
Producer: incrementing count to 2
Producer: incrementing count to 3
Producer: incrementing count to 4
Producer: incrementing count to 5
Producer: terminating
private volatile static int sCount = 0;
Consumer: detected count change 0
Producer: incrementing count to 1
Consumer: detected count change 1
Producer: incrementing count to 2
Consumer: detected count change 2
Producer: incrementing count to 3
Consumer: detected count change 3
Producer: incrementing count to 4
Consumer: detected count change 4
Producer: incrementing count to 5
Consumer: detected count change 5
Consumer: terminating
Producer: terminating
public class SharedObject {
public volatile int sharedVariable = 0;
}
public class SharedObject {
public int counter = 0;
}