我正尝试在2个螺距之间插入一个5秒钟的间隙,然后在另一个IE上输入我的第一螺距“ X”,则将延迟5秒钟,然后将另一个螺距打印为“ Y”,再次为5秒延迟,然后显示“ X”,表示已进行了30次。
import java.lang.*;
import java.util.concurrent.TimeUnit;
class PingPong implements Runnable
{ String word;
PingPong(String s){
word = s;
}
public void run()
{
try
{
for(int i = 0; i<30; i++)
{
System.out.println(word);
Thread.sleep(100) ;
}
} catch (InterruptedException e)
{ e.printStackTrace(); }
}
public static void main(String[] args){
Runnable p1 = new PingPong("ping");
Thread t1 = new Thread(p1);
t1.start();
Runnable p2 = new PingPong("pong");
Thread t2 = new Thread(p2);
t2.start();
}
}
答案 0 :(得分:1)
除非引入某种同步机制,否则线程彼此独立。因此,您需要做的第一件事就是更改PingPong类以使其同步,每个线程都将在该同步上等待。
我们将此对象称为ball
。您可以在PingPong
的构造函数中传递它。它可以是任何您想要的对象(甚至只是对象),也可以为其创建自己的小型类。
然后在循环中,您可以执行以下操作:
synchronized(ball) {
System.out.println(word);
Thread.sleep(5000);
}
Thread.sleep(1000);
这样,每个线程将阻塞5秒钟,直到允许另一个线程“拿起”球的监视器并输出其文字为止。
第二次睡眠是任意的,但很重要,因此同一线程不会再次获得监视器。
一种稍微复杂但更正确的方法是使用第二个ReentrantLock
。同样,您必须将其与上一个ball
对象一起传递给构造函数。我们称之为lock
。
lock.lock();
synchronized(ball) {
try {
System.out.println(word);
} finally {
lock.unlock();
}
Thread.sleep(5000);
}
unlock()
位于finally
块中,以确保如果引发任何异常,则锁定不会永远保持锁定状态。
System.out
实际上并不需要放在try
块中,但这使代码更加优雅,而不是空的try
。 sleep()
必须在外面,以确保另一个线程在该线程处于休眠状态时通过第一个锁进入。
这可确保如果线程 Ping 处于睡眠状态,则线程 Pong 将占用lock
,因此它将紧邻synchronized
内。块。当 Ping 醒来并退出synchronized
块时,即使巧合地在 Pong 之前安排了时间,它也无法继续执行,因为它可以t取下锁,必须等待 Pong 进入synchronized
块中并输出其字。