我被要求执行一个名为“ping”和“pong”的pingpong游戏(意思是ping之前没有pong)10次。意思是,控制台中的最终输出应该是:“ping!(1)”,“pong!(1)”,“ping!(2)”,“pong!(2)”等。
需求是用信号量,reetrantlock和倒计时锁定实现gamepingpongthread。
我的问题是打印订单并不总是如我所要求的那样,我想知道我做错了什么。
以下是代码:
// Import the necessary Java synchronization and scheduling classes.
import java.util.concurrent.Semaphore;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition;
/**
* @class PingPongRight
*
* @brief This class implements a Java program that creates two
* instances of the PlayPingPongThread and start these thread
* instances to correctly alternate printing "Ping" and "Pong",
* respectively, on the console display.
*/
public class PingPongRight
{
/**
* @class SimpleSemaphore
*
* @brief This class provides a simple counting semaphore
* implementation using Java a ReentrantLock and a
* ConditionObject.
*/
static public class SimpleSemaphore
{
private int mPermits;
private ReentrantLock lock = new ReentrantLock();
private Condition isZero = lock.newCondition();
/**
* Constructor initialize the data members.
*/
public SimpleSemaphore (int maxPermits)
{
mPermits = maxPermits;
}
/**
* Acquire one permit from the semaphore.
*/
public void acquire() throws InterruptedException
{
lock.lock();
while (mPermits == 0)
isZero.await();
mPermits--;
lock.unlock();
}
/**
* Return one permit to the semaphore.
*/
void release() throws InterruptedException
{
lock.lock();
try {
mPermits++;
isZero.signal();
} finally {
lock.unlock();
}
}
}
/**
* Number of iterations to run the test program.
*/
public static int mMaxIterations = 10;
/**
* Latch that will be decremented each time a thread exits.
*/
public static CountDownLatch latch = new CountDownLatch(2);
/**
* @class PlayPingPongThread
*
* @brief This class implements the ping/pong processing algorithm
* using the SimpleSemaphore to alternate printing "ping"
* and "pong" to the console display.
*/
public static class PlayPingPongThread extends Thread
{
private String message;
private SimpleSemaphore semaphore;
/**
* Constructor initializes the data member.
*/
public PlayPingPongThread (String msg, SimpleSemaphore pingOrPong)
{
message = msg;
semaphore = pingOrPong;
}
/**
* Main event loop that runs in a separate thread of control
* and performs the ping/pong algorithm using the
* SimpleSemaphores.
*/
public void run ()
{
for (int i = 1 ; i <= mMaxIterations ; i++) {
try {
semaphore.acquire();
System.out.println(message + "(" + i + ")");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
latch.countDown();
}
}
/**
* The main() entry point method into PingPongRight program.
*/
public static void main(String[] args) {
try {
// Create the ping and pong SimpleSemaphores that control
// alternation between threads.
SimpleSemaphore pingSemaphore = new SimpleSemaphore(mMaxIterations);
SimpleSemaphore pongSemaphore = new SimpleSemaphore(mMaxIterations);
System.out.println("Ready...Set...Go!");
// Create the ping and pong threads, passing in the string
// to print and the appropriate SimpleSemaphores.
PlayPingPongThread ping = new PlayPingPongThread("Ping!", pingSemaphore);
PlayPingPongThread pong = new PlayPingPongThread("Pong!", pongSemaphore);
// Initiate the ping and pong threads, which will call the run() hook method.
ping.start();
pong.start();
// Use barrier synchronization to wait for both threads to finish.
latch.await();
}
catch (java.lang.InterruptedException e)
{}
System.out.println("Done!");
}
}
提前致谢
答案 0 :(得分:8)
我的问题是打印订单并不总是如我所要求的那样,我想知道我做错了什么。
我认为你的问题是ping和pong线程都在获取并释放自己的信号量。我认为您需要将两个信号量传递给两个线程。每个帖子都会调用acquire()
上的acquireSemaphore
和release()
上的releaseSemaphore
。
acquireSemaphore.acquire();
System.out.println(message + "(" + i + ")");
releaseSemaphore.release();
线程看起来像:
public PlayPingPongThread (String msg, SimpleSemaphore acquireSemaphore,
SimpleSemaphore releaseSemaphore)
然后将线程初始化为:
// ping acquires on the ping, releases the pong
PlayPingPongThread ping = new PlayPingPongThread("Ping!", pingSemaphore, pongSemaphore);
// pong acquires on the pong, releases the ping
PlayPingPongThread pong = new PlayPingPongThread("Pong!", pongSemaphore, pingSemaphore);
pingSemaphore
应该从1开始,而pong应该从0开始。
ping
首先致电acquire()
上的pingSemaphore
,然后就会给出。ping
打印出ping。ping
在release()
上调用pongSemaphore
。pong
(假设您的信号量代码当然有效)。pong
打印pong
。pong
在release()
上调用pingSemaphore
。答案 1 :(得分:0)
您还可以使用“重入”锁定条件来实现乒乓游戏,这与等待通知非常相似。
package com.example.thread;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class PingPongUsingReentrantCondition {
private static ReentrantLock lock = new ReentrantLock(true);
private Condition conditionMet = lock.newCondition();
public static void main(String[] args) {
PingPongUsingReentrantCondition pingPong = new PingPongUsingReentrantCondition();
int times = 10;
Thread t1 = new Thread(() -> pingPong.pingpong("Ping!", times));
Thread t2 = new Thread(() -> pingPong.pingpong("Pong!", times));
t1.start();
t2.start();
}
public void pingpong(String s, int times) {
int counter = 1;
while(counter<=times) {
run(s, counter);
counter = counter+1;
}
}
public void run(String s, int counter) {
lock.lock();
try {
conditionMet.await(2, TimeUnit.SECONDS);
System.out.println(s + "(" + counter + ")");
conditionMet.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}