当前状态:(2013年10月10日):已解决。
问题: 我正在研究线程并决定随机实现一些任务。 所以谷歌发现了这个assignment
描述(消除游戏逻辑,主要目的是专注于线程) 我有四个玩家围成一圈,卡片在它们之间划分。他们将洗牌他们的牌(这个任务是为了简单,显然游戏逻辑是不同的),一旦完成他们的卡他们可以举手他们完成,然后所有人都可以重复这个过程,在技术术语线程将等待其他人完成,然后到达或完成最后的人可以通知其他人继续......
我的代码状态:
主要类别:
public class RunGame implements Runnable{
volatile int count=0;
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public static void main(String arg[]){
RunGame obj= new RunGame();
Player p1= new Player("Player 1");
Player p2= new Player("Player 2");
Player p3= new Player("Player 3");
Player p4= new Player("Player 4");
Runnable r1 = new ThreadRun(p1,obj);
Runnable r2 = new ThreadRun(p2,obj);
Runnable r3 = new ThreadRun(p3,obj);
Runnable r4 = new ThreadRun(p4,obj);
Thread t1 = new Thread(r1,"Player 1");
Thread t2 = new Thread(r2,"Player 2");
Thread t3 = new Thread(r3,"Player 3");
Thread t4 = new Thread(r4,"Player 4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
型号:
public class Player {
private String player;
public Player(String name) {
this.player=name;
}
//getter and setter
}
商务舱:
public class PlayerRun implements Runnable{
Player player;
RunGame mainObj;
public PlayerRun(Player player,RunGame main) {
this.player=player;
this.mainObj=main;
}
public void run() {
while(true){
synchronized (mainObj) {
int count=mainObj.getCount();
System.out.println(Thread.currentThread().getName()+"...."+count);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mainObj.setCount(++count);
System.out.println(Thread.currentThread().getName()+" Done...."+count);
}
synchronized (mainObj) {
try {
if(mainObj.getCount()<=3)
mainObj.wait();//current thread will wait till it is awaken by notify.
else if(mainObj.getCount()>3){
System.out.println(Thread.currentThread().getName()+" is last one to enter and awake all");
mainObj.setCount(0);
mainObj.notifyAll();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"==============================");
}
}}
输出:
Player 1....0
Player 1 Done....1
Player 4....1
Player 4 Done....2
Player 3....2
Player 3 Done....3
Player 2....3
Player 2 Done....4
Player 2 is last one to enter and awake all
Player 2==============================
Player 2....0
Player 3==============================
Player 4==============================
Player 2 Done....1
Player 1==============================
Player 4....1
Player 4 Done....2
Player 3....2
Player 3 Done....3
Player 1....3
Player 1 Done....4
Player 1 is last one to enter and awake all
Player 1==============================
Player 3==============================
Player 1....0
Player 1 Done....1
Player 4==============================
Player 3....1
Player 2==============================
Player 3 Done....2
Player 2....2
Player 2 Done....3
Player 4....3
Player 4 Done....4
Player 4 is last one to enter and awake all
Player 4==============================
Player 4....0
Player 3==============================
Player 2==============================
Player 4 Done....1
Player 1==============================
Player 2....1
Player 2 Done....2
Player 3....2
Player 3 Done....3
Player 1....3
Player 1 Done....4
Player 1 is last one to enter and awake all
Player 1==============================
Player 3==============================
Player 1....0
Player 1 Done....1
Player 2==============================
Player 4==============================
Player 3....1
Player 3 Done....2
Player 4....2
Player 4 Done....3
Player 2....3
Player 2 Done....4
Player 2 is last one to enter and awake all
Player 2==============================
Player 3==============================
Player 2....0
Player 1==============================
Player 4==============================
Player 2 Done....1
Player 4....1
Player 4 Done....2
Player 1....2
Player 1 Done....3
Player 3....3
Player 3 Done....4
Player 3 is last one to enter and awake all
Player 3==============================
Player 3....0
Player 1==============================
Player 3 Done....1
Player 4==============================
Player 1....1
Player 2==============================
Player 1 Done....2
Player 2....2
Player 2 Done....3
Player 4....3
Player 4 Done....4
Player 4 is last one to enter and awake all
Player 4==============================
Player 2==============================
Player 3==============================
Player 1==============================
Player 4....0
Player 4 Done....1
Player 1....1
Player 1 Done....2
Player 3....2
Player 3 Done....3
Player 2....3
Player 2 Done....4
Player 2 is last one to enter and awake all
答案 0 :(得分:1)
您的同步块会为每个玩家单独锁定,因此锁定必然会失败。 见:
synchronized (this) {
try {
System.out.println(Thread.currentThread().getName()+" work in progress..."+count);
for(int i =0;i<=3;i++){
Thread.sleep(1000);
}
count++;
System.out.println(Thread.currentThread().getName()+" work Done..."+count);
} 所有玩家都应该锁定同一个物体。
因此,您可以为所有玩家创建一个公共锁,并将其传递给PlayerRun以解决此问题。
编辑:
根据以下评论,用户要求是
“如果我理解正确,他希望球员做他们的工作 (同时)然后每个完成的人都会等到最后一个 完成了他的工作,他们又重新开始了。“
这增加了一个全新的问题。在这种情况下,同步块采用的方法是不正确的,因为它将意味着相互排斥的方法。
您应该使用CyclicBarrier
,这是所有线程的单一障碍,您可以实现此目标。
答案 1 :(得分:1)
- 不同的线程同时进入同步块。
醇>
同步机制用于在多线程环境中协调访问共享变量。每当多个线程访问给定的状态变量,并且其中一个必须写入它时,它们都必须使用同步协调它们对它的访问。
您在synchronized(this)
类的run
方法中使用PlayerRun
,该方法表示只有一个thread of execution
可以在任何给定的时间点执行此代码块。由于您创建了4个PlayerRun
个实例并让它们彼此独立运行,因此它们会同时输入自己的synchronized
个块。
您再次将count
变量定义为静态:
static volatile int count=0;
您需要使用PlayerRun
的运行时类作为监视器,因为它不依赖于PlayerRun
的任何特定实例。因此count
变量的更改应在PlayerRun.class
上同步:
synchronized(PlayerRun.class)
{
count++;
}
一旦一个线程完成了他的工作,它应该递增count变量并且count = 4当前线程应该通知其他3个等待,最终我想实现之前发生的关系。
方法wait, notify and notifyAll
为一组线程提供了一种等待特定条件变为真的方法(这些都是实例方法)。在某个对象上使用wait
时,表示当前执行的线程将等待某个条件成为该对象的真实状态。而notify
和notifyAll
用于通知等待同一对象的其他线程。当多个线程使用同一个对象时,使用这些方法集,并且编写代码的方式与此方法不同。
我的建议是在所有线程中使用一个共享counter
。这可以通过在count
类中定义RunGame
变量并将其实例传递给PlayerRun
runnables来实现:
public class RunGame implements Runnable{
private int count=0;
...
public synchronized void increaseCount() throws InterruptedException {
count++;
}
....
@Override
public void run() {
Runnable r1 = new PlayerRun(player1, this);
...
}
}
您可以更改PlayerRun
:
public class PlayerRun implements Runnable{
RunGame runGame;
...
public PlayerRun(Player player, RunGame runGame) {
this.player = player;
this.runGame = runGame;
}
...
@Override
public void run() {
// DO YOUR WORK
runGame.increaseCount();
}
}
答案 2 :(得分:1)
实际上每个线程都会在轮次上更新计数,所以在计数3之后它将变为3,当第4个线程进入时它将增加到4并通知所有其他人重复该过程。
上述声明是从comment
复制的。而且我认为这会改变最初的需求,因为现在你想重新重复这个过程。为此,您需要使用两个方法替换increaseCount
方法,一个用于使线程等待count < 4
,另一个用于在计数变为4时通知等待线程:
//threads will increment the value of count by 1 and will wait if its value is
//less than 4.
public synchronized void increaseCount() throws InterruptedException {
count++;
if (count < 4) {
wait();
}
}
//4th thread will come inside this method, it will set the count value to 0
//and will notify other threads
public synchronized void releaseCount() throws InterruptedException {
if (count >= 3) {
count = 0;
notifyAll();
}
}
并将PlayerRun
更改为:
public class PlayerRun implements Runnable{
RunGame runGame;
...
public PlayerRun(Player player, RunGame runGame) {
this.player = player;
this.runGame = runGame;
}
...
@Override
public void run() {
while (true) {
// DO YOUR WORK
runGame.releaseCount();
runGame.increaseCount();
}
}
}
您无需在synchronized
run
方法中使用PlayerRun
关键字。 synchronized
关键字用于协调对共享变量的访问。您在count
中拥有共享变量RunGame
,您可以使用synchronized
和increaseCount
上的relaesCount
关键字向其提供同步访问权。