有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何让线程只添加到一个带有同步

我一直在尝试做一些简单的事情,比如让两个线程添加到一个arraylist,但无论出于什么原因,我都无法让它工作。我有同步方法和使用集合。已同步列表,但仍显示它正在打印两个单独的数组。为了更好地理解运行两个线程访问一个arrayList,我编写了一个简短的程序。如果有人能说明我犯了什么错误,我将不胜感激

这是主课

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

public class RunThreads {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newCachedThreadPool();
        int[] numbers1 = {0, 2, 4, 6, 8};
        int[] numbers2 = {1, 3, 5, 7, 9};
        executor.execute(new ThreadToRun(numbers1));
        executor.execute(new ThreadToRun(numbers2));
        executor.shutdown();
    }
}

以下是Theadatorun类:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ThreadToRun implements Runnable {
    List<Integer> list = Collections.synchronizedList(new ArrayList<Integer>());
    private int[] array;

    public ThreadToRun(int[] array) {
        this.array = array;
    }

    public void run() {
        list = adder(array);
        for(int i=0; i<list.size(); i++){
            System.out.print(list.get(i)+"("+i+")"); //print out the element at i and the index 
        }                                            //to see if there are two arrays with the same index
    }

    public  List<Integer> adder(int [] a){
        List<Integer> list = Collections.synchronizedList(new ArrayList<Integer>());
        for (int array : a) {
            synchronized(list){
                list.add(array);
            }
        }
        return list;
    }
}

共 (5) 个答案

  1. # 1 楼答案

    在这里,您将创建两个“theadatorun”实例,每个实例将实例化list的一个新实例(如下所述)

    List<Integer> list = Collections.synchronizedList(new ArrayList<Integer>());
    

    此外,在加法器方法中,您正在执行以下操作:

    List<Integer> list = Collections.synchronizedList(new ArrayList<Integer>());
    

    这将再次创建一个新列表,并覆盖实例中的现有列表

    可能的解决方案:

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    public class ThreadToRun implements Runnable {
        List<Integer> list;
        private int[] array;
    
        public ThreadToRun(int[] array, List<Integer> list) {
            this.array = array;
            this.list = list;
        }
    
        public void run() {
            for (int array : a) {
                list.add(array);
            }
        }
    }
    
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class RunThreads {
        public static void main(String[] args) {
            ExecutorService executor = Executors.newCachedThreadPool();
            int[] numbers1 = {0, 2, 4, 6, 8};
            int[] numbers2 = {1, 3, 5, 7, 9};
    
            List<Integer> list = Collections.synchronizedList(new ArrayList<Integer>());
    
            ThreadToRun t1 = new ThreadToRun(numbers1, list);
            ThreadToRun t2 = new ThreadToRun(numbers1, list);
    
            executor.execute(t1);
            executor.execute(t2);
            executor.shutdown();
    
            // print the list out
            for(int i=0; i<list.size(); i++){
                System.out.print(list.get(i) + " found at location ("+i+")");
            }
        }
    }
    
  2. # 2 楼答案

    您正在为每个“ThreadToRun”实例创建新的ArrayList。所以它们不是相同的列表

    你需要在跑步者之间分享一份名单

  3. # 3 楼答案

    public class ThreadToRun implements Runnable {
        List<Integer> list = Collections.synchronizedList(new ArrayList<Integer>());
    

    listThreadToRun的实例成员。每次创建ThreadToRun时,它都会将其list设置为一个新的ArrayList。这意味着每个线程都有自己的列表。这两个线程没有共享一个列表

    有很多方法可以让它共享一个列表,但其中一些是不推荐的(单例模式),还有一些是非常讨厌的(static类成员)。最干净的方法可能是将列表作为构造函数的参数。然后RunThreads将创建列表并将其传递给两个线程的构造函数:

        List<Integer> list = Collections.synchronizedList(new ArrayList<Integer>());
        executor.execute(new ThreadToRun(numbers1, list));
        executor.execute(new ThreadToRun(numbers2, list));
    

    在{}中:

    List<Integer> list;
    private int[] array;
    
    public ThreadToRun(int[] array, List<Integer> list) {
        this.array = array;
        this.list = list;
    }
    

    现在,您的线程将使用相同的列表

    还有一个问题我一开始没注意到,因为你在你的adder中使用了一个局部变量list,这让我很困惑。看起来adder创建了第二个列表,您也将其称为list,我认为它将被添加到第一个列表中。但由于这是一个局部变量,它不会在线程之间共享;因此synchronized在错误的地方。我不确定你的意图是什么。如果希望adder实际添加到主list,那么不能使用名为list的局部变量,因为这样会隐藏列表。但是如果你想要adder仅仅创建一个新列表,并且让run将新列表添加到主列表中,那么synchronized必须位于run中,围绕着添加到主列表中的代码。不幸的是,我不太确定你想做什么

  4. # 4 楼答案

    我建议你做两件事:

    1. 更重要的一点。您正在调用类似list = adder(array);的方法。因此,它将始终替换ArrayList的内容。列表中的任何早期数据都将被方法返回的新列表替换

    相反,你可以用下面的方法

    list.add(adder(array));

    1. 创建列表的另一种方法是将列表声明为static。这样,你的两个线程都会很常见,它们会进入同一个列表
  5. # 5 楼答案

    您创建了同步集合的两个实例(在ThreadToRun的第6行中)ThreadToRun的每个实例一个。您必须在所有线程之间共享同一实例。有几种方法可以做到这一点。例如,这可以通过使列表保持静态(我不喜欢这样)或通过构造函数将实例传递给类来实现