我目前正在学习多线程,并且发现一些有趣的东西我无法解释。据我所知,如果两个线程正在访问静态变量,他们可以将自己的副本制作到缓存中。Thread1对其本地高速缓存中静态变量的更新不会反映在thread2缓存的静态变量中。
因此,cracker.java中我的ISFOUND静态变量应该是静态和挥发性的,但这并不重要,因为当此退出条件设置为true时,所有线程都立即停止。有人可以向我解释吗?
hashdecryptor.java
public class HashDecryptor {
private List<Thread> threads = new ArrayList<>();
// some other fields
public HashDecryptor() {
createThreads();
}
private void createThreads() {
long max = (long) (Math.pow(26, numberOfChars));
int n = numberOfThreads;
for (int i = 0; i < n; ++i) {
if (i == 0) {
threads.add(new Thread(new Cracker(hashToDecrypt, (max * i / n), (max * (i + 1) / n))));
} else {
threads.add(new Thread(new Cracker(hashToDecrypt, (max * i / n) + 1, (max * (i + 1) / n))));
}
}
}
public void startDecryting() {
for (Thread t : threads) {
t.start();
}
}
}
cracker.java
public class Cracker implements Runnable {
// Some other fields
private static boolean isFound;
public Cracker(String hashToDecrypt, long start, long end) {
this.hashToDecrypt = hashToDecrypt;
this.start = start;
this.end = end;
}
@Override
public void run() {
decrypt();
}
public void decrypt() {
LocalTime startTime = LocalTime.now();
long counter = start;
while (!isFound && counter <= end) {
if (match(counter)) {
isFound = true;
printData(generatePassword(counter), startTime);
}
counter++;
}
}
}
静态变量:在对象的上下文中使用,其中一个对象的更新会反映在同一类的所有其他对象中,而在线程的上下文中不反映一个线程的更新到静态变量将立即反映对所有线程的更改(在其本地缓存中(。 如果两个线程(假设T1和T2(正在访问相同的对象并更新一个变量,该变量被声明为静态对象,则表示T1和T2可以在其各自的缓存中制作同一对象的本地副本(包括静态变量(,因此T1对其本地高速缓存中的静态变量进行的更新不会反映在T2缓存的静态变量中。
挥发性变量:如果两个线程(假设T1和T2(正在访问相同的对象并更新一个变量,该变量被声明为挥发性对象除了被声明为挥发性的变量。因此,挥发性变量将只有一个主副本,该副本将通过不同的线程更新,并且一个线程对挥发性变量进行的更新将立即反射到另一个线程。
因此,cracker.java中我的ISFOUND静态变量应该是静态和波动的,但这没关系,因为当此退出条件设置为true时,所有线程都立即停止。有人可以向我解释吗?
您可以通过多种方法获得偶然的同步,这可能是为此解释的。首先,您的应用程序可能会争夺在硬件上运行的其他应用程序的CPU资源,并且该应用程序可能会被互换。也许您的线程比CPU多。两者都可能导致脏内存的脏内存,当线程交换时核心内存。
另一种可能的情况是,您的线程正在越过其他内存障碍,例如调用其他synchronized
方法或访问其他volatile
字段。例如,我想知道这个语句,因为某些输入/输出流具有同步类。
printData(generatePassword(counter), startTime);
您可以尝试删除数据的打印,以查看您的应用程序行为是否更改。
我告诉你它可以正常工作,我确实用Sysout进行了验证。这就是这个奇怪的事情,这就是为什么我问这个问题:(
完美的例子。System.out
是PrintStream
,它是synchronized
类,因此调用println()
会导致您的线程跨越读取和写入内存障碍,以更新您的static
字段。重要的是要注意,任何任何内存屏障会影响缓存的内存的所有。越过任何读取记忆障碍迫使所有缓存的内存都可以从中央内存更新。越过任何写入障碍迫使所有局部肮脏的内存都写入中心。
问题是当您删除System.out
方法或应用程序停止调用synchronized
类,然后static
变量未正确更新。因此,您不能依靠它,但确实会发生。