0

当前状态:(2013 年 10 月 10 日):已解决。

问题: 我正在研究线程并决定随机执行一些任务。所以谷歌一个,找到了这个作业

说明(消除游戏逻辑,主要目的是专注于线程)我有四个玩家围成一圈,他们之间已经分配了卡片。他们将洗牌(这个任务是为了简单起见,显然游戏逻辑不同),一旦所有的牌都完成了,他们可以举手表示他们已经完成,然后所有人都可以重复这个过程,从技术角度来说,线程将等待其他人完成,然后最后到达或完成的人可以通知其他人继续......

我的代码状态:

  1. 不同的线程同时进入同步块。
  2. 一旦一个线程完成他的工作,它应该增加count变量并且count=4当前线程应该通知其他3个等待,最终我想实现happens-before关系。

主类:

   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
4

3 回答 3

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个等待,最终我想实现happens-before关系。

这些方法wait, notify and notifyAll为一组线程提供了一种等待特定条件变为真的方式(这些都是实例方法)。当您wait在某个对象上使用时,这意味着当前执行线程将等待该对象的某个条件变为真。而notifyandnotifyAll用于通知等待同一对象的其他线程。当多个线程处理同一个对象并且您编写代码的方式与此方法不同时,会使用这些方法集。

我的建议是使用counter所有线程之间共享的一个。这可以通过count在类中定义一个变量RunGame并将其实例传递给PlayerRun可运行对象来实现:

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();
    }
}
于 2013-10-10T07:57:17.557 回答
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为所有线程使用 , 一个屏障,您可以实现这一点。

于 2013-10-09T10:28:39.097 回答
1

实际上每个线程都会轮流更新计数,所以在计数 3 之后它将变为 3,当第 4 个线程进入时,它会将其增加到 4,并通知所有其他线程重复该过程。

上面的语句是从你的comment. 我认为这改变了最初的要求,因为现在你想重新重复这个过程。为此,您需要将increaseCount方法替换为两种方法,一种是在计数变为 4 时让线程等待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();
    }
    }
}

您不需要synchronizedrun. PlayerRunsynchronized关键字用于协调对共享变量的访问。你有你的共享变量countRunGame你可以通过使用synchronized关键字 onincreaseCount和来提供同步访问relaesCount

于 2013-10-11T08:23:03.823 回答