我已将两个进程关键部分解决方案应用于两个线程而不是进程。我的代码是:
class Main
{
static boolean flag[];
static int turn;
static int count;
synchronized static void print(char ch,int n)
{
int i;
System.out.println(ch);
for(i=0;i<n;i++){
System.out.println(i);
}
}
public static void main(String[] args) throws IOException
{
flag = new boolean[2];
flag[0] = flag[1] = false;
turn = 0;
count = 0;
ThreadLevelOne t1 = new ThreadLevelOne('a');
ThreadLevelTwo t2 = new ThreadLevelTwo('b');
t1.start();
t2.start();
}
static class ThreadLevelOne extends Thread{
private char ch;
public ThreadLevelOne(char ch){
this.ch = ch;
}
public void run(){
while(true)
{
flag[0] = true;
turn = 1;
while(flag[1] && turn == 1);
print(ch,3);
count++;
System.out.println("Counter is : " + count);
flag[0] = false;
}
}
}
static class ThreadLevelTwo extends Thread{
private char ch;
public ThreadLevelTwo(char ch){
this.ch = ch;
}
public void run()
{
while(true)
{
flag[1] = true;
turn = 0;
while(flag[0] && turn == 0);
print( ch, 4);
count++;
System.out.println("Counter is : " + count);
flag[1] = false;
}
}
}
}
执行上述代码时,它不会无限运行,而是在每次执行时在任意计数器值处停止。这是两进程解决方案对线程的有效应用吗?如果是,那么为什么程序在任意计数器值处停止?如果不是,那么如何在线程中实现这一点?
在codeBlind回答后编辑:
即使我不增加计数器值,程序也会在一定时间后停止
最佳答案
您是并发执行非原子操作(特别是count++
)以及在每个线程中使用标志的方式的受害者。但为了简单起见,我们来谈谈 count++
。 ++
运算符实际上执行三个命令,每个命令都有自己的时钟周期:
- 读取
计数
的值 - 将
1
添加到从count
检索到的值 - 将新值存储到
count
您看到的问题是这些命令在两个线程之间交错造成的。当线程 B 尝试读取新的 count
值时,线程 A 可能尚未存储该值。
一个快速修复方法是使用 AtomicInteger
进行计数,而不是原始 int
- AtomicInteger
保证整数操作的线程安全。
编辑
此代码中还存在其他竞争条件。每个线程的 while 循环参数(例如 flag[0] &&turn == 0
)都是非原子的,但两个线程都能够修改 turn
。您留下了这样一种可能性:一个线程可能会在另一个线程的 while 参数完全计算之前设置轮次,从而导致您的线程陷入死锁。
如果您只想保证每个线程都不能位于 while 循环内,而另一个线程则位于 while 循环内,那么您应该将每个 while
循环编写为如下所示:
while(true){
synchronized(Main.class){
print( ch, 4);
count++;
System.out.println("Counter is : " + count);
}
}
如果您想保证每个线程必须“轮流”,您应该考虑使用 wait()
和 notify()
。
关于java - 两个进程临界区错误解决方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36432922/