代码之家  ›  专栏  ›  技术社区  ›  rhymes

如何让线程操作相同的java列表

  •  0
  • rhymes  · 技术社区  · 2 年前

    我有一个类,在这个类中,我定义了一个带有添加和删除方法的列表,如下所示:

    public class listClass{
        private List<T> someList = new ArrayList<>();
    
        public void add(){
            //adds to list
        }
    
        public void delete(){
            //deletes from list
        }
    }
    

    我有另一个类,我在其中定义了两个线程和一个对象,从中我可以访问我的列表。一个线程应使用add方法连续添加到列表中,另一个线程应使用delete方法连续删除列表中相应的线程号:

    public class threadClass extends Thread{
        private int threadNumber;
        public ThreadClass(int threadNumber){
            this.threadNumber = threadNumber;
        }
    
        listClass listClassObject = new listClass();
    
        public void run(){
            if(threadNumber == 1){
                while(true){/*add*/}
            }
            else if(threadNumber ==2){
                    while(true){/*delete*/}
            }
        }
    }
    

    我如何做到这一点,使两个线程都在处理同一个列表?

    我当前的实现有一个不同的类,它有一个main方法,我在其中调用线程,如下所示:

    public static void main(String[] args){
            threadClass threadForAddingMediaFiles = new threadClass(1);
            threadClass threadForDeletionMediaFiles = new threadClass(2);
            threadForAddingMediaFiles.start();
            threadForDeletionMediaFiles.start();
    

    当前实现的问题是,每个线程都会创建自己的列表实例(我很清楚,因为列表在同一个类中),因此每个线程都会操作自己的列表,而不是一个通用列表。

    2 回复  |  直到 2 年前
        1
  •  2
  •   Paolo    2 年前

    我认为这是因为你在每个threadClass对象中实例化一个新的listClass,所以当你修改列表时,你实际上是在每个线程中修改它们自己的“本地”副本。 尝试在main函数中实例化list,然后将其传递给线程,这样就有一个list类的实例由两个线程操作。

    public static void main(String[] args){
        listClass myList = new listClass();
        threadClass threadForAddingMediaFiles = new threadClass(1, myList);
        threadClass threadForDeletionMediaFiles = new threadClass(2, myList);
        threadForAddingMediaFiles.start();
        threadForDeletionMediaFiles.start();
    

    然后修改线程实现:

    public class threadClass extends Thread{
    private int threadNumber;
    private listClass listToHandle;
    public ThreadClass(int threadNumber, listClass listToHandle){
        this.threadNumber = threadNumber;
        this.listToHandle = listToHandle;
    }
    
    public void run(){
        if(threadNumber == 1){
            while(true){/*add*/}
        }
        else if(threadNumber ==2){
                while(true){/*delete*/}
        }
    }
    }
    

    最后,记住将add和delete方法都作为synchronized放在listclass中,否则在并发访问方面会遇到一些问题。

    public class listClass{
    private List<T> someList = new ArrayList<>();
    
    public synchronized void add(){
        //adds to list
    }
    
    public synchronized void delete(){
        //deletes from list
    }
    }
    

    你也可以看看 CopyOnWriteArrayList ,这是ArrayList的线程安全实现。然而,正如文档中所说,这通常是一个成本高昂的实现,可能不是一个适合您的问题的解决方案。

        2
  •  0
  •   Basil Bourque    2 年前

    在现代Java中,我们很少讨论 Thread 直接上课。相反,使用Java5中添加的Executors框架。这已经包含在许多现有的问题和答案中,所以请搜索以了解更多信息。

    将你的任务定义为 Runnable 而不是 线 .

    至于跨线程共享列表管理器,请创建一个实例。确保列表管理器是线程安全的。您当前的实现不是线程安全的。一种解决方案是将add和delete方法都标记为 synchronized .

    将列表管理器对象的一个实例传递给 可运行的 任务对象。每个 可运行的 将对该列表管理器的引用保留为私有成员字段。然后,您的所有Runnable共享同一个列表管理器。

    提交你所有的申请 可运行的 反对 ExecutorService .

    同样,这一切已经被多次报道。搜索以了解更多信息。

        3
  •  0
  •   HienNg    2 年前

    你可以使用集合。synchronizedList()则无需将Synchronized添加到add/delete方法中。创建ListClass的一个实例,然后将其传递给两个线程的构造函数。

    class listClass
    {
          private List<T> someList = Collections.synchronizedList(new ArrayList<>());    
    }