考虑以下简单示例:
public class Example extends Thread {
private int internalNum;
public void getNum() {
if (internalNum > 1)
System.out.println(internalNum);
else
System.out.println(1000);
}
public synchronized modifyNum() {
internalNum += 1;
}
public void run() {
// Some code
}
}
假设代码执行分为两个线程。假设,会发生以下事件序列:
- 第一个线程访问
getNum
方法并缓存当前为0的internalNum
。 - 与此同时,第二个线程访问
modifyNum
方法获取锁,将internalNum
更改为 1 并退出释放锁。 - 现在,第一个线程继续执行并打印
internalNum
。
问题是控制台上会打印什么?
我的猜测是,这个假设的示例将导致 1000 打印在控制台上,因为只有在进入或离开同步块(synchronized block)时才会在特定线程上强制进行读写刷新。因此,第一个线程将愉快地使用它的缓存值,而不知道它已更改。
我知道使 internalNum
volatile 可以解决可能的问题,但我只是想知道它是否真的有必要。
最佳答案
Let's say code execution is split in two threads. It doesn't exit. However a ressource (method, fields) may be accessed in concurrent way by two threads.
我认为你把东西混在一起了。您的类扩展了Thread
,但您的问题是关于通过并发线程访问同一实例的资源。
这是适合您的问题的代码。
线程之间的共享资源:
public class SharedResource{
private int internalNum;
public void getNum() {
if (internalNum > 1)
System.out.println(internalNum);
else
System.out.println(1000);
}
public synchronized modifyNum() {
internalNum += 1;
}
public void run() {
// Some code
}
}
线程和运行代码:
public class ThreadForExample extends Thread {
private SharedResource resource;
public ThreadForExample(SharedResource resource){
this.resource=resource;
}
public static void main(String[] args){
SharedResource resource = new SharedResource();
ThreadForExample t1 = new ThreadForExample(resource);
ThreadForExample t2 = new ThreadForExample(resource);
t1.start();
t2.start();
}
}
您的问题:
Hypothetically, following sequence of events occurs:
First thread accesses the getNum method and caches the internalNum which is 0 at the moment. At the very same time second thread accesses modifyNum method acquiring the lock, changes the internalNum to 1 and exits releasing the lock. Now, first thread continues it execution and prints the internalNum
在您的场景中,您给人的印象是 modifyNum()
方法执行会阻止其他线程访问非同步方法,但事实并非如此。
getNum()
未同步。因此,线程不需要获取对象上的锁来执行它。在这种情况下,输出仅取决于哪个线程首先执行了指令:
internalNum += 1;
或
System.out.println(internalNum);
关于Java同步与数据一致性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41533796/