在下面的代码中,当我执行producercon
类时,有时执行卡住,看起来像死锁。但是,如果我使get_flag ()
同步,那么就没有这样的问题了。
我无法弄清楚怎么会有问题。 flag
可以是true或false,因此只有producer
或consumer
中的一个会进入if
语句。在其中一个进入if
之后,它将进入具有对象r
的监视器(两者都使用相同的对象引用进行初始化)。 r
函数调用increment_decrement ()
对象被修改的唯一问题,get_flag ()
同时读取标志,但即使这样,它也不会进入if
在那次迭代中{1}},但它会在下一次迭代时进入if
块,即使第一个线程没有离开监视器,它也会在那里等待它(在synchronized
之前块)。
如果get_flag ()
未成为synchronized
,程序如何暂停/挂起?
import java.io.*;
class resource
{
private boolean res, flag;
resource ()
{
flag=false;
}
boolean get_flag ()
{
return flag;
}
void increment_decrement (String s,boolean t)
{
res=t;
flag=t;
try
{
System.out.print("\n"+s+":"+res);
Thread.sleep(200);
}
catch(InterruptedException e)
{
}
}
}
class producer implements Runnable
{
resource r1;
Thread t1;
producer(resource r)
{
r1 = r;
t1 = new Thread(this);
t1.start();
}
public void run ()
{
while (true)
{
if(r1.get_flag () == false)
{
synchronized(r1)
{
r1.increment_decrement("Producer",true);
}
}
}
}
public void waitForThread () throws InterruptedException
{
t1.join ();
}
}
class consumer implements Runnable
{
resource r2;
Thread t2;
consumer(resource r)
{
r2 = r;
t2 = new Thread (this);
t2.start();
}
public void run()
{
while (true)
{
if(r2.get_flag () == true)
{
synchronized(r2)
{
r2.increment_decrement("Consumer",false);
}
}
}
}
public void waitForThread () throws InterruptedException
{
t2.join ();
}
}
public class producercon
{
public static void main(String args[])
{
try
{
System.out.print("PRESS CTRL+C TO TERMINATE\n");
resource r = new resource();
consumer c = new consumer(r);
producer p = new producer(r);
c.waitForThread ();
p.waitForThread ();
}
catch(InterruptedException e)
{
}
}
}
答案 0 :(得分:6)
你对get_flag()的调用不是线程安全的,也不是volatile。这意味着在线程1的高速缓存中,它可以是真的,而在线程2的高速缓存中它可以是假的。
答案 1 :(得分:4)
您需要将布尔值设为volatile
或AtomicBoolean
。现在,多个线程正在尝试访问无法同步的布尔值。
答案 2 :(得分:0)
这种生产者/消费者实施非常奇怪。
生产者和消费者都没有等待资源处于适当的状态,并且资源访问没有得到很好的保护(标志应该被一些锁保护以确保它在线程之间的可见性。)
改进此设计的一种方法是使用标准等待/通知系统。另一种方法是在资源中使用信号量,以确保在一个给定时间只有一个线程可以访问资源。最后,您可以使用更高级别的构造,例如java.util.concurrent.SynchronousQueue,将一些数据直接从生产者传递给使用者。