Java 如何解决这个僵局
我有两条线。这两个线程必须调用Java 如何解决这个僵局,java,multithreading,concurrency,deadlock,Java,Multithreading,Concurrency,Deadlock,我有两条线。这两个线程必须调用send()(然后调用receive())或receive(),但是这段代码有一个很好的死锁。有没有办法解决这个问题 public class C { public static void main(String[] args) { Z z1=new Z(); Z z2=new Z(); z1.setZ(z2); z2.
send()
(然后调用receive()
)或receive()
,但是这段代码有一个很好的死锁。有没有办法解决这个问题
public class C
{
public static void main(String[] args)
{
Z z1=new Z();
Z z2=new Z();
z1.setZ(z2);
z2.setZ(z1);
z1.start();
z2.start();
}
}
class Z extends Thread
{
Z z;
Object lock=new Object();
public void setZ(Z zz)
{
z=zz;
}
public void run()
{
new Thread()
{
public void run()
{
z.send();
}
}.start();
new Thread()
{
public void run()
{
z.send();
}
}.start();
}
public void send()
{
synchronized(lock)
{
System.out.println("[Z] Send");
z.receive();
}
}
public void receive()
{
synchronized(lock)
{
System.out.println("[Z] Receive");
}
}
}
这里的僵局很明显
z1
产生两个新线程;我们把它们叫做T1和T2。它还创建了一个名为lock
的对象实例,我们称之为L1。
z2
也这样做;让我们调用线程T3和T4以及锁L2
现在,让我们假设*,T1首先开始
public void send()
{
synchronized(lock)
{
System.out.println("[Z] Send");
}
z.receive();
}
编辑
如果锁旨在保护所有实例不并发执行,则可以使用一个跨所有线程共享的锁,因此:
class Z extends Thread
{
static final Object lock=new Object();
...
}
现在我们只有一个锁实例,让我们将其称为L0,再看看上面的步骤是如何运行的:
*线程启动顺序永远不能保证与调用
start()
方法的顺序相同,但在这种情况下,在所有可能的情况下都有死锁的风险。最简单的方法是使用静态类级锁,而不是非静态锁,它只需要一行更改
private static Object lock=new Object();
首先,让我们看看问题的根源:
在本例中,死锁发生是因为两个Z实例彼此持有锁(共享资源),并且都在等待对方的资源完成其任务。而且,没有人能够离开它所持有的资源上的锁
由于锁是非静态的,z的每个实例都有自己的锁,因此在调用send()时允许两个z实例一起获取实例级锁,这会导致死锁,因为调用receive()需要对已经锁定的对象进行锁定
这可以通过使用静态/类级别锁来解决。通过在静态锁上同步,您将同步整个类方法和属性(与实例方法和属性相反)。
换句话说,Z类的所有实例都将共享该对象上锁定的对象,因此没有两个实例能够同时锁定该对象
一旦将锁定对象设置为静态,程序将能够按如下方式运行:
死锁在哪里?z1和z2都启动。两者都在同步块内调用send()。然后它们都调用receive,但othet线程位于另一个同步块中。但是您没有向另一个线程发送任何内容,而是在与
send()
相同的线程上调用receive()
。一个线程只需按住另一个线程,直到它完成receive()
。您对代码的期望是什么?一个线程应该等待另一个线程完成吗?或者别的什么?这个练习到底想证明什么?你说的是“两个线程”,但我看到了七个线程:主线程启动两个线程,每个线程启动两个线程