volatile 变量没有给出预期的输出
volatile variable is not giving expected output
我读到易失性变量副本将由所有线程共享,一旦执行完成,更新值将由每个线程获取,但是在下面使用线程池的程序中没有给出我预期的输出,可以有人告诉我原因吗?
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class Task implements Runnable{
volatile int v1=10;
private String name;
public Task(String name) {
this.name=name;
}
public synchronized void run() {
v1=v1+10;
System.out.println(name +"is entered "+v1);
}
}
public class ThreadPoolTest {
public static void main(String[] args) {
Runnable r1 = new Task("Thread 1");
Runnable r2 = new Task("Thread 2");
Runnable r3 = new Task("Thread 3");
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.execute(r1);
executor.execute(r2);
executor.execute(r3);
executor.shutdown();
}
}
outPut:
Thread 1is entered 20
Thread 2is entered 20
Thread 3is entered 20
but if we change from volatile to static its giving below output:
Thread 1is entered 20
Thread 3is entered 30
Thread 2is entered 40
观察到的结果是正确的,因为您正在创建三个独立的 Task
实例,它们拥有自己的 name
变量副本。
因此,尽管它们是 volatile
,但其他线程未更新值,执行特定实例的线程是更新 v1
字段的线程。
如果 v1
设为静态,则它成为 class
成员,因此显然线程将更新变量 v1
.
的相同副本
我们可以使用 AtomicInteger
来安全地更新和获取值,而不是在 run
方法上使用 synchronized
。
class Task implements Runnable{
private final AtomicInteger v1 = new AtomicInteger(10);
private String name;
public void run() {
System.out.println("Thread is: " + Thread.currentThread().getName() + " " + v1.addAndGet(10));
}
}
public class ThreadPoolTest{
public static void main(String[] args) {
Runnable r1 = new Task();
ExecutorService executor = Executors.newFixedThreadPool(3);
executor.execute(r1);
executor.execute(r1);
executor.execute(r1);
executor.shutdown();
}
}
这是因为v1
是一个实例变量,每个任务都有自己的。
所以在示例中,您增加了 v1
个不同的实例。 static
也不可靠,因为您正在对 Task
的实例进行同步,因此它仍然存在竞争条件(例如,每个线程都可能读取 v1
的值为 10,即使在static volatile
)
可能你需要AtomicInteger
简而言之,volatile或Atomic Variables是解决当两个或多个线程试图访问相同的不一致(Memory Consistency Errors)的解决方案资源(可以是static/non-static)同时。
https://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html
在您的情况下,您没有与多个线程共享您的任务。因此无需使用 volatile 关键字或原子变量。如果你想与多个线程共享你的变量,那么你可以使用 Atomic 变量而不是 volatile。
那么,当你向变量添加 static 关键字时会发生什么?
静态变量可用于 class 的所有对象。
https://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/variables.html
我读到易失性变量副本将由所有线程共享,一旦执行完成,更新值将由每个线程获取,但是在下面使用线程池的程序中没有给出我预期的输出,可以有人告诉我原因吗?
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class Task implements Runnable{
volatile int v1=10;
private String name;
public Task(String name) {
this.name=name;
}
public synchronized void run() {
v1=v1+10;
System.out.println(name +"is entered "+v1);
}
}
public class ThreadPoolTest {
public static void main(String[] args) {
Runnable r1 = new Task("Thread 1");
Runnable r2 = new Task("Thread 2");
Runnable r3 = new Task("Thread 3");
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.execute(r1);
executor.execute(r2);
executor.execute(r3);
executor.shutdown();
}
}
outPut:
Thread 1is entered 20
Thread 2is entered 20
Thread 3is entered 20
but if we change from volatile to static its giving below output:
Thread 1is entered 20
Thread 3is entered 30
Thread 2is entered 40
观察到的结果是正确的,因为您正在创建三个独立的 Task
实例,它们拥有自己的 name
变量副本。
因此,尽管它们是 volatile
,但其他线程未更新值,执行特定实例的线程是更新 v1
字段的线程。
如果 v1
设为静态,则它成为 class
成员,因此显然线程将更新变量 v1
.
我们可以使用 AtomicInteger
来安全地更新和获取值,而不是在 run
方法上使用 synchronized
。
class Task implements Runnable{
private final AtomicInteger v1 = new AtomicInteger(10);
private String name;
public void run() {
System.out.println("Thread is: " + Thread.currentThread().getName() + " " + v1.addAndGet(10));
}
}
public class ThreadPoolTest{
public static void main(String[] args) {
Runnable r1 = new Task();
ExecutorService executor = Executors.newFixedThreadPool(3);
executor.execute(r1);
executor.execute(r1);
executor.execute(r1);
executor.shutdown();
}
}
这是因为v1
是一个实例变量,每个任务都有自己的。
所以在示例中,您增加了 v1
个不同的实例。 static
也不可靠,因为您正在对 Task
的实例进行同步,因此它仍然存在竞争条件(例如,每个线程都可能读取 v1
的值为 10,即使在static volatile
)
可能你需要AtomicInteger
简而言之,volatile或Atomic Variables是解决当两个或多个线程试图访问相同的不一致(Memory Consistency Errors)的解决方案资源(可以是static/non-static)同时。
https://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html
在您的情况下,您没有与多个线程共享您的任务。因此无需使用 volatile 关键字或原子变量。如果你想与多个线程共享你的变量,那么你可以使用 Atomic 变量而不是 volatile。
那么,当你向变量添加 static 关键字时会发生什么?
静态变量可用于 class 的所有对象。
https://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/variables.html