Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 更改存储在不同线程上的列表中的对象的字段_Java_Multithreading_Concurrency_Synchronization_Thread Safety - Fatal编程技术网

Java 更改存储在不同线程上的列表中的对象的字段

Java 更改存储在不同线程上的列表中的对象的字段,java,multithreading,concurrency,synchronization,thread-safety,Java,Multithreading,Concurrency,Synchronization,Thread Safety,所以我有两个线程,线程A和线程B。线程A包含一个包含我的对象的ArrayList。我想做的是:在线程B上,创建新对象并将其添加到该列表中。然后在线程A上更改该对象的字段。之后,在线程B上读取该更改的字段。但遗憾的是,当我在线程B上读取该字段时,我得到了在对象构造函数上创建的默认值。那么,如何读取新的值呢 使现代化 一些信息:由我使用的名为Bukkit的API启动的应用程序上执行的onEnable方法,绑定到Bukkit的所有内容都在线程A上执行,线程A是Bukkit的主线程 Main.class

所以我有两个线程,线程A和线程B。线程A包含一个包含我的对象的ArrayList。我想做的是:在线程B上,创建新对象并将其添加到该列表中。然后在线程A上更改该对象的字段。之后,在线程B上读取该更改的字段。但遗憾的是,当我在线程B上读取该字段时,我得到了在对象构造函数上创建的默认值。那么,如何读取新的值呢

使现代化 一些信息:由我使用的名为Bukkit的API启动的应用程序上执行的onEnable方法,绑定到Bukkit的所有内容都在线程A上执行,线程A是Bukkit的主线程

Main.class:

private static ExecutorService executorService;
private static List<Confirmation> confirmations;

public void onEnable() {
    executorService = Executors.newCachedThreadPool();
    confirmations = new ArrayList<>();
}

public static ExecutorService getExecutorService() {
    return executorService;
}

public static Confirmation createConfirmation(CommandSender sender, String command, String[] args) {
    removeConfirmation(sender, command);
    Confirmation confirmation = new Confirmation(sender, command, args);
    confirmations.add(confirmation);
    return confirmation;
}

public static void removeConfirmation(CommandSender commandSender, String command) {
    confirmations.removeIf(confirmation -> confirmation.getSender().getName().equals(commandSender.getName()) && confirmation.getCommand().equalsIgnoreCase(command));
}

public static Confirmation getConfirmation(CommandSender commandSender, String command) {
    return confirmations.stream().filter(confirmation -> confirmation.getSender().getName().equals(commandSender.getName()) && confirmation.getCommand().equalsIgnoreCase(command)).findFirst().orElse(null);
}

public static Confirmation createConfirmationIfNull(CommandSender commandSender, String command, String[] args) {
    Confirmation confirmation = getConfirmation(commandSender, command);
    return confirmation != null ? confirmation : createConfirmation(commandSender, command, args);
}
Command.class:

@CommandHandler(name = "rank", usage = "/rank <set|prefix>", requiredRank = Rank.ADMINISTRATOR)
public void rank(CommandSender sender, Command command, String s, String[] args) { //Always called on Thread A
    String str = args[0];
    RankCommandAction action = Arrays.stream(RankCommandAction.values()).filter(rankCommandAction -> rankCommandAction.getName().equalsIgnoreCase(str)).findFirst().orElse(null);
    if (action == null) {
        sender.sendMessage(ChatColor.RED + "Usage: /rank <set|prefix>");
        return;
    }

    Main.getExecutorService().submit(() -> action.getConsumer().accept(sender, args)); //Thread B
}

private enum RankCommandAction {

    SET_PREFIX("prefix", (CommandSender sender, String[] args) -> {
        CommandConfirmationEvent event = new CommandConfirmationEvent(sender, "rank", args, ChatColor.RED + "Are you sure?");
        Bukkit.getPluginManager().callEvent(event);

        if (!event.isCancelled()) {
            sender.sendMessage("Prefix changed");
        }
    }),


    SET_RANK("set", (CommandSender sender, String[] args) -> {
        CommandConfirmationEvent event = new CommandConfirmationEvent(sender, "rank", args, ChatColor.RED + "Are you sure?");
        Bukkit.getPluginManager().callEvent(event);

        if (!event.isCancelled()) {
            sender.sendMessage("Changed rank");
        }
    });
这是调用事件时实际执行的操作:

if (!event.getConfirmation().isConfirmed()) {
    event.getCommandSender().sendMessage("Please confirm");
    return;
}
Main.removeConfirmation(event.getConfirmation());
最后,这是在线程A上确认的命令:

@CommandHandler(name = "confirm")
public void confirm(CommandSender sender, Command cmd, String str, String[] args) { //Always called on Thread A
    Confirmation confirmation = findConfirmation(sender, "confirm", args);

    if (confirmation != null) {
        confirmation.setConfirmed(true);
        String[] arg = confirmation.getArgs();
        Bukkit.dispatchCommand(sender, confirmation.getCommand() + (arg != null && arg.length > 0 ? " " + StringUtils.merge(arg, " ") : "")); //This runs the "rank" command again
        Main.removeConfirmation(confirmation);
    }
}

private Confirmation findConfirmation(CommandSender sender, String[] args) {
    List<Confirmation> list = Main.getConfirmations(sender);

    if (list.isEmpty())
        return null;

    Confirmation confirmation;
    if (list.size() > 1) {
        if (args.length == 0) {
            sender.sendMessage(ChatColor.RED + "Since you have multiple confirmations awaiting, you must specify the confirmation you want to confirm.");
            sender.sendMessage(ChatColor.RED + "Usage: /confirm <command>");
            sender.sendMessage(ChatColor.RED + "Awaiting confirmations: " + StringUtils.merge(list.stream().map(Confirmation::getCommand).toArray(String[]::new), ", ") + ".");
            return null;
        } else {
            Confirmation foundConfirmation = list.stream().filter(confirmation1 -> confirmation1.getCommand().equalsIgnoreCase(args[0])).findFirst().orElse(null);
            if (foundConfirmation == null) {
                sender.sendMessage(ChatColor.RED + "You don't have any confirmations for the command '" + args[0] + "'.");
                return null;
            } else {
                confirmation = foundConfirmation;
            }
        }
    } else {
        confirmation = list.get(0);
    }

    return confirmation;
}

您应该在两个线程上使用相同的对象实例,并在访问此对象时同步它们

在您的描述中没有任何意义线程包含Arraylist。如果是局部变量,线程B永远无法访问它。

根据给定的代码,它可能会在此行objects.get0.setNameTEST抛出IndexOutOfBounds异常; 原因 提交给executor服务的任务将在其自己的时间轴上运行,而不是休眠1000 主线程睡眠200不会有帮助,即使增加到2000也未必有帮助 应该怎么做 创建两个倒计时闩锁 将一个闩锁传递给提交的任务 设置后,它将在闩锁上倒计时,并等待其他闩锁 main将在闩锁上等待,闩锁将按任务倒计时 主线程一旦收到任务线程的通知,将在其他锁存器上执行更新和倒计时 现在任务将被通知并打印更新的值 静态类MyObject{ 易变字符串值; MyObjectString值{ 这个值=值; } } 公共静态无效字符串[]args{ 最终列表对象=新的ArrayList; ExecutorService ExecutorService=Executors.newSingleThreadExecutor; CountDownLatch updateLatch=新的CountDownLatch1; CountDownLatch addLatch=新的CountDownLatch1; executorService.submit->{ objects.addnew MyObjectNAME; 试一试{ addlack.countDown; 等待; System.out.printlnobjects.get0.value;//此打印名称 }捕获异常e{ e、 打印跟踪; } }; 试一试{ 等待; objects.get0.value=测试; 倒计时; }捕获异常e{ e、 打印跟踪; } }
我发现了问题:我正在从confirm命令的列表中删除对象,它在再次运行rank命令之前删除了对象。这会导致第二列命令执行找不到确认对象。

在使用多个线程时,不要首先使用ArrayList;除非您采用某种同步,否则我使用CopyOnWriteArrayList和Collections.synchronizedListnew ArrayList,但两者似乎都不起作用,我们需要猜测您的代码?你能提供一个最小的,可重复的例子吗?添加了一个例子代码这个打印的名字在我的情况下不会发生,当我运行这个。可复制的部分在哪里?我的意思是,列表是静态的,在线程A上创建。请参阅我的示例代码。谢谢您纠正我,但正如我所说,上面的代码只是一个示例,它打印测试时没有错误。我的原始代码和它相似,只是睡觉和其他东西,它不工作
if (!event.getConfirmation().isConfirmed()) {
    event.getCommandSender().sendMessage("Please confirm");
    return;
}
Main.removeConfirmation(event.getConfirmation());
@CommandHandler(name = "confirm")
public void confirm(CommandSender sender, Command cmd, String str, String[] args) { //Always called on Thread A
    Confirmation confirmation = findConfirmation(sender, "confirm", args);

    if (confirmation != null) {
        confirmation.setConfirmed(true);
        String[] arg = confirmation.getArgs();
        Bukkit.dispatchCommand(sender, confirmation.getCommand() + (arg != null && arg.length > 0 ? " " + StringUtils.merge(arg, " ") : "")); //This runs the "rank" command again
        Main.removeConfirmation(confirmation);
    }
}

private Confirmation findConfirmation(CommandSender sender, String[] args) {
    List<Confirmation> list = Main.getConfirmations(sender);

    if (list.isEmpty())
        return null;

    Confirmation confirmation;
    if (list.size() > 1) {
        if (args.length == 0) {
            sender.sendMessage(ChatColor.RED + "Since you have multiple confirmations awaiting, you must specify the confirmation you want to confirm.");
            sender.sendMessage(ChatColor.RED + "Usage: /confirm <command>");
            sender.sendMessage(ChatColor.RED + "Awaiting confirmations: " + StringUtils.merge(list.stream().map(Confirmation::getCommand).toArray(String[]::new), ", ") + ".");
            return null;
        } else {
            Confirmation foundConfirmation = list.stream().filter(confirmation1 -> confirmation1.getCommand().equalsIgnoreCase(args[0])).findFirst().orElse(null);
            if (foundConfirmation == null) {
                sender.sendMessage(ChatColor.RED + "You don't have any confirmations for the command '" + args[0] + "'.");
                return null;
            } else {
                confirmation = foundConfirmation;
            }
        }
    } else {
        confirmation = list.get(0);
    }

    return confirmation;
}