我已经将两个流程关键部分解决方案应用于两个线程而不是流程。我的代码是:
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的回答后编辑:
即使我不增加计数器值,程序也会在一段时间后停止
答案 0 :(得分:0)
您是同时执行非原子操作的受害者,特别是count++
,以及您在每个线程中使用标记的方式。但为了简单起见,让我们谈谈count++
。 ++
运算符实际上执行三个命令,每个命令都在它们自己的时钟周期中:
count
1
添加到从count
count
您看到的问题是这些命令在两个线程之间交错的结果。在线程B尝试读取它时,线程A可能没有存储新的count
值。
快速解决方法是将AtomicInteger
用于计数而不是原始int
- AtomicInteger
保证整数操作的线程安全。
修改强>
此代码中还有其他竞争条件。每个线程的while循环参数(例如flag[0] && turn == 0
)都是非原子的,但两个线程都能够修改turn
。你已经开放了一个线程可以在完全评估参数的同时在另一个线程之前设置转弯的可能性,从而导致你的线程陷入僵局。
如果你只想保证每个线程都不能在while循环中,而另一个线程是,那么你应该改为编写每个while
循环看起来像这样:
while(true){
synchronized(Main.class){
print( ch, 4);
count++;
System.out.println("Counter is : " + count);
}
}
如果您想保证每个帖子必须&#34;轮流使用#34;,您应该考虑使用wait()
和notify()
。
答案 1 :(得分:-1)
好的,所以我想出来了,问题是每个线程都需要暂停才能运行其他线程。
而不是仅使用以下方式旋转cpu:
while(flag[0] && turn == 0);
您需要通过调用sleep方法来暂停线程。
while(flag[0] && turn == 0){
try {
this.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}