java - 理解java多线程同步

标签 java multithreading

我无法理解以下代码的输出。 我的理解是输出不会有任何特定的顺序,但 PlayerX startedPlayerXPlayerX dead 应该按顺序排列。而且我们应该有所有玩家应该在缓冲区日志中并且应该在最后打印。 但有时序列是 PlayerX 启动PlayerX 死亡 然后是 PlayerX 并且这些情况下玩家名称不在缓冲区字符串中。有人可以指出我缺少什么吗?

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Game {

    public static void main(String[] args) {
        Ball gameBall = new Ball();
        ExecutorService executor = Executors.newFixedThreadPool(5);
        Player[] players = new Player[50];
        for (int i = 0; i < players.length; i++) {
            Player playerTemp = new Player("Player" + i, gameBall);
            executor.submit(playerTemp);
            players[i] = playerTemp;
            System.out.println(players[i].getName1() + " started");
        }

        for (int i = 0; i < players.length; i++) {

            try {
                players[i].join();
                System.out.println(players[i].getName1() + " died");
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        /*
                 * here all thread should die and following line should display
          *all player name 
                 * without any particular order
         and should be last line.
         */

        executor.shutdown();

        System.out.println(gameBall.getLog());
    }

}

...

class Player extends Thread {

    private final String name;
    private final Ball ball;

    public Player(String aName, Ball aBall) {
        name = aName;
        ball = aBall;
    }

    @Override
    public void run() {
        ball.kick(name);
    }

    /**
     * @return the name
     */
    public String getName1() {
        return name;
    }

}

...

class Ball {

    private volatile StringBuffer log;

    public Ball() {
        log = new StringBuffer();
    }

    public synchronized void kick(String aPlayerName) {

        log.append(aPlayerName + " ");
        System.out.println(aPlayerName);

    }

    public String getLog() {
        return log.toString();
    }

}

最佳答案

首先:如果您向 Player.run() 方法添加额外的 Thread.sleep(100);,您的代码的可能性将大大增加行为错误。

您对多线程的理解其实是正确的。 但是,您对 players[i].join(); 的调用没有达到预期的效果,因为您从未启动线程 players[i]

相反,您将其提交给 ExecutorService。此 ExecutorService 通过从其现有线程之一调用其 run() 方法来执行 Player。在您的例子中,它们是执行所有玩家工作的 5 个线程。

要获得所需的结果,您有两种可能性:

  1. 不要使用ExecutorService,而是直接调用start():

    for (int i = 0; i < players.length; i++) {
        Player playerTemp = new Player("Player" + i, gameBall);
        playerTemp.start();
        players[i] = playerTemp;
        System.out.println(players[i].getName1() +" started");
    }
    
  2. 使用executor.awaitTermination(..)而不是Thread.join():

    executor.shutdown();
    while(!executor.isTerminated()) {
        try {
            executor.awaitTermination(1, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    

关于java - 理解java多线程同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41025558/

相关文章:

multithreading - 线性系统求解器在 Julia 中是否也像在 Matlab 中一样是多线程的?以及如何在 Julia 中对其进行 "multithread"处理?

c# - 如何使用 Task 设置最大并发线程数

java - 如何暂停一个 Runnable 直到另一个相同类型的任务完成?

java - NullPointer 异常存储库 Spring Boot Jpa

java - 如何生成具有泊松分布的离散随机事件?

Java流无法识别类型

java - 如何并行运行任务并在第一个任务失败时等待第二个任务,否则回复并让第二个任务运行

java - 使用 ASM 库覆盖 Java 字节码中的局部变量名称

java - 如何命名xs :elements in the generated wsdl?

java - Android 线程实例化