如何让线程操作同一个列表Java

How to let threads manipulate the same list Java

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

public class listClass{
    private List<T> someList = new ArrayList<>();

    public void add(){
        //adds to list
    }

    public void delete(){
        //deletes from list
    }
}

我还有另一个 class,我在其中定义了两个线程和一个对象,从中我可以访问我的列表。一个线程应使用 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*/}
        }
    }
}

我怎样才能让两个线程都处理同一个列表?

我当前的实现有一个不同的 class,它有一个 main 方法,我在这里调用线程:

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

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

在现代 Java 中,我们很少直接称呼 Thread class。相反,使用添加到 Java 5 中的执行器框架。许多现有的问题和答案中都涵盖了这一点,因此请搜索以了解更多信息。

将您的任务定义为 Runnable 而不是 Thread

至于跨线程共享您的列表管理器,请举一个例子。确保您的列表管理员是 thread-safe。您当前的实施不是 thread-safe。一种解决方案是将添加和删除方法都标记为 synchronized.

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

将所有 Runnable 对象提交给 ExecutorService

同样,所有这一切都已经讲过很多次了。搜索以了解更多信息。

我认为发生这种情况是因为您在每个 threadClass 对象中实例化了一个新的 listClass,因此当您修改列表时,您实际上是在每个线程中修改它们自己的“本地”副本。 尝试在您的主函数中实例化该列表,然后将其传递给您的线程,这样您将拥有一个由您的两个线程操作的列表实例 class。

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*/}
    }
}
}

最后记得把你的添加和删除方法放在你的列表中class同步,否则你会遇到一些关于并发访问的问题。

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 的 thread-safe 实现。但是,如文档中所述,这通常是一个昂贵的实现,可能不是解决您问题的合适方法。

你可以使用 Collections.synchronizedList() 然后不需要添加同步到 add/delete 方法。创建 ListClass 的实例,然后将其传递给 2 个线程的两个构造函数。

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