vik*_*.rk 1 java concurrency multithreading pthreads javac
根据我的理解,如果硬件支持多处理器系统上的高速缓存一致性,则对其他处理器上运行的线程可以看到对共享变量的写入.为了测试这个,我用Java和pThreads编写了一个简单的程序来测试它
public class mainTest {
public static int i=1, j = 0;
public static void main(String[] args) {
/*
* Thread1: Sleeps for 30ms and then sets i to 1
*/
(new Thread(){
public void run(){
synchronized (this) {
try{
Thread.sleep(30);
System.out.println("Thread1: j=" + mainTest.j);
mainTest.i=0;
}catch(Exception e){
throw new RuntimeException("Thread1 Error");
}
}
}
}).start();
/*
* Thread2: Loops until i=1 and then exits.
*/
(new Thread(){
public void run(){
synchronized (this) {
while(mainTest.i==1){
//System.out.println("Thread2: i = " + i); Comment1
mainTest.j++;
}
System.out.println("\nThread2: i!=1, j=" + j);
}
}
}).start();
/*
* Sleep the main thread for 30 seconds, instead of using join.
*/
Thread.sleep(30000);
}
}
/* pThreads */
#include<stdio.h>
#include<pthread.h>
#include<assert.h>
#include<time.h>
int i = 1, j = 0;
void * threadFunc1(void * args) {
sleep(1);
printf("Thread1: j = %d\n",j);
i = 0;
}
void * threadFunc2(void * args) {
while(i == 1) {
//printf("Thread2: i = %d\n", i);
j++;
}
}
int main() {
pthread_t t1, t2;
int res;
printf("Main: creating threads\n");
res = pthread_create(&t1, NULL, threadFunc1, "Thread1"); assert(res==0);
res = pthread_create(&t2, NULL, threadFunc2, "Thread2"); assert(res==0);
res = pthread_join(t1,NULL); assert(res==0);
res = pthread_join(t2,NULL); assert(res==0);
printf("i = %d\n", i);
printf("Main: End\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我注意到pThread程序总是结束.(我为thread1测试了不同的睡眠时间).然而,Java程序只结束了几次; 大部分时间都没有结束.如果我在java程序中取消注释Comment1,那么它会一直结束.此外,如果我使用volatile,那么在所有情况下它都会以java结尾.
所以我的困惑是,
如果在硬件中完成高速缓存一致性,那么除非编译器对代码进行优化,否则"i = 0"应该对其他线程可见.但是如果编译器优化了代码,那么我不明白为什么线程有时会结束而有时不会结束.另外,添加System.out.println似乎会改变行为.
任何人都可以看到Java所做的编译器优化(这不是由C编译器完成的),这会导致这种行为吗?
还有一些额外的编译器必须做的事情,即使硬件已经支持它,也能获得Cache一致性吗?(如启用/禁用)
我应该默认使用Volatile用于所有共享变量吗?
我错过了什么吗?欢迎提出任何其他意见.
如果在硬件中完成高速缓存一致性,那么除非编译器对代码进行优化,否则"i = 0"应该对其他线程可见.但是如果编译器优化了代码,那么我不明白为什么线程有时会结束而有时不会结束.另外,添加System.out.println似乎会改变行为.
注意:javac没有优化,所以不要考虑静态优化.
您正在锁定与您正在修改的对象无关的不同对象.由于您正在修改的字段不是volatileJVM优化器可以随意动态优化它,无论您的硬件可以提供哪种支持.
由于这是动态的,它可能会也可能不会优化您在该线程中不更改的字段的读取.
任何人都可以看到Java所做的编译器优化(这不是由C编译器完成的),这会导致这种行为吗?
优化很可能是将读取缓存在寄存器中或完全消除代码.此优化通常需要大约10-30毫秒,因此您正在测试在程序完成之前是否已发生此优化.
还有一些额外的编译器必须做的事情,即使硬件已经支持它,也能获得Cache一致性吗?(如启用/禁用)
您必须正确使用该模型,忘记编译器将优化您的代码的想法,并理想地使用并发库来传递线程之间的工作.
public static void main(String... args) {
final AtomicBoolean flag = new AtomicBoolean(true);
/*
* Thread1: Sleeps for 30ms and then sets i to 1
*/
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(30);
System.out.println("Thread1: flag=" + flag);
flag.set(false);
} catch (Exception e) {
throw new RuntimeException("Thread1 Error");
}
}
}).start();
/*
* Thread2: Loops until flag is false and then exits.
*/
new Thread(new Runnable() {
@Override
public void run() {
long j = 0;
while (flag.get())
j++;
System.out.println("\nThread2: flag=" + flag + ", j=" + j);
}
}).start();
}
Run Code Online (Sandbox Code Playgroud)
版画
Thread1: flag=true
Thread2: flag=false, j=39661265
Run Code Online (Sandbox Code Playgroud)
我应该默认使用Volatile用于所有共享变量吗?
几乎从不.如果你只设置了一次,那么它会有效.但是,使用锁定通常更有用.
| 归档时间: |
|
| 查看次数: |
397 次 |
| 最近记录: |