我正在学习线程安全。我写了一个例子并得到了一个问题。
首先,我的main()函数是相同的:
public class ThreadSafe {
public static void main(String[] args) {
System.out.println("Thread Safe");
SafeSharedRunnable r = new SafeSharedRunnable();
// Access the same resource
Thread tA = new Thread(r);
Thread tB = new Thread(r);
Thread tC = new Thread(r);
Thread tD = new Thread(r);
tA.start();
tB.start();
tC.start();
tD.start();
}
}
然后我有两个版本Runnable,其中synchronized()放在不同的地方,因此,一个版本有效,一个版本没有。
工作版本:
public class SafeSharedRunnable implements Runnable {
int count = 5;
@Override
public void run() {
// Thread Safe, must be outside of while(), why?
synchronized ("") {
while (count > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
}
System.out.println("Current value is: " + count--);
}
}
}
}
正确的结果:
run:
Thread Safe
Current value is: 5
Current value is: 4
Current value is: 3
Current value is: 2
Current value is: 1
BUILD SUCCESSFUL (total time: 0 seconds)
非工作版本:
public class SafeSharedRunnable implements Runnable {
int count = 5;
@Override
public void run() {
while (count > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
}
// Thread Safe
synchronized ("") {
System.out.println("Current value is: " + count--);
}
}
}
}
错误的结果:
run:
Thread Safe
Current value is: 5
Current value is: 4
Current value is: 2
Current value is: 3
Current value is: 1
Current value is: 0
Current value is: -1
Current value is: -2
BUILD SUCCESSFUL (total time: 0 seconds)
如您所见,不同的synchronized()块的不同位置会导致不同的结果。根据我的理解,关键资源冲突应该发生在这行代码上:
System.out.println("Current value is: " + count--);
但为什么我必须在while()块之外放置synchronized()?这是否意味着我应该同步所有包含变量的代码" count"?感谢您的详细解释。
我不认为这与竞争条件问题重复,因为我并不是在询问有关多线程的任何一般知识。相反,这是一个关于多线程如何进入代码流的详细问题。
答案 0 :(得分:3)
如果synchronized
仅包装System.out.println
,那么您只能保证打印语句一次发生一个。因此,所有线程都可以在运行开始时立即整个while
,然后再减少任何内容。一旦所有线程都在while
循环内,它们将运行打印和递减,而不管count
。
但是,如果您将while (count > 0) {
包裹在synchronized
中,那么一次只能有一个帖子进入while
。这意味着每个线程必须在执行while循环的全部内容之前检查计数,包括减量。
答案 1 :(得分:1)
您的代码问题是
mawk -v OFS='\t' '
NR==1 {
nbfield=(NF-1)
for(i=1;i<NF;i++)
ID[i]=$(i+1)
print $1 OFS "ID" OFS "VALUE"
next
}
{
numrecord=((NR-1)%nbfield)
numrecord = numrecord ? numrecord : nbfield
for(i=0;i<=nbfield;i++)
val[ID[i],numrecord]=$(i+1)
}
numrecord==nbfield {
for(i=1;i<=nbfield;i++)
for(j=1;j<=nbfield;j++)
print val[ID[0],j] OFS ID[j] OFS val[ID[j],i]
}
' infile
这四个主题将依次打印// if four threads come here and now count is 1
synchronized ("") {
System.out.println("Current value is: " + count--);
}
导致输出count
。
试试此代码
1 0 -1 -2
虽然你的工作版本得到了正确的输出,但是你同步了while循环,这意味着只有一个线程可以完成所有工作。这不是多线程应该做的事情。
答案 2 :(得分:0)
如果你把synchronized ("")
置于块中,那么多个线程同时看到count = 1并且所有都将进入while循环并减少计数并导致错误的结果。如果你使计数原子整数然后它将对所有人可见线。