Java 两个线程读取相同的列表,但来自不同的端

Java 两个线程读取相同的列表,但来自不同的端,java,multithreading,listiterator,Java,Multithreading,Listiterator,我有一个列表,我需要遍历两个线程的列表。一个从上到下读取,另一个从下到上读取。当它们相交时,阅读应该停止 对于列表的迭代,我可以使用ListIterator,但我无法思考这些线程将如何从同一个列表中读取?由于线程仅在读取,因此不需要使用列表的线程安全版本 要确保线程在相交时停止读取,您需要同步线程,因此在读取另一项之前,线程应检查该项是否可用。实现这一点的一种简单方法是在每个线程中存储当前索引,并让另一个线程访问该索引(确保同步该索引)。但这将导致大量的开销 更好的办法是分批工作。将列表划分为部

我有一个列表,我需要遍历两个线程的列表。一个从上到下读取,另一个从下到上读取。当它们相交时,阅读应该停止


对于列表的迭代,我可以使用ListIterator,但我无法思考这些线程将如何从同一个列表中读取?

由于线程仅在读取,因此不需要使用列表的线程安全版本

要确保线程在相交时停止读取,您需要同步线程,因此在读取另一项之前,线程应检查该项是否可用。实现这一点的一种简单方法是在每个线程中存储当前索引,并让另一个线程访问该索引(确保同步该索引)。但这将导致大量的开销


更好的办法是分批工作。将列表划分为部分,例如16个项目。然后,线程可以在需要检查交叉点之前读取整个批处理。

您可以对列表进行分区,其中一个线程将从0读取到一半,第二个线程将从0读取到一半+1直到最后

class PrintList implements Runnable{

    private List list = new ArrayList();
    public PrintList(List list){
        this.list = list;
    }


    @Override
    public void run() {
     if(Thread.currentThread().getName() != null && Thread.currentThread().getName().equalsIgnoreCase("thread1")){
         int mid =list.size()/2;
         for(int i = 0; i< mid;i++){
            // System.out.println("Thread 1 "+list.get(i));
         }
     }else if(Thread.currentThread().getName() != null && Thread.currentThread().getName().equalsIgnoreCase("thread2")){

         for(int i = mid; i<list.size(); i++){
             //System.out.println("Thread 2 "+list.get(i));
         }
     }  
    }   
}
类PrintList实现可运行{
私有列表=新的ArrayList();
公共打印列表(列表){
this.list=列表;
}
@凌驾
公开募捐{
if(Thread.currentThread().getName()!=null&&Thread.currentThread().getName().equalsIgnoreCase(“thread1”)){
int mid=list.size()/2;
对于(int i=0;i对于(int i=mid;i,如果考虑到线程a处理的项目总数和线程B处理的项目总数最终将等于列表中的项目数量,则有一种简单的方法来解决此问题

因此,如果你有一个计数器,每当一个线程想要处理下一个元素时,它都会递减,那么你知道一旦计数器达到零,你就完成了

public class MyThreadSyncer {
  protected final AtomicInteger elementCount;

  public MyThreadSyncer(final Collection c) {
    elementCount = new AtomicInteger(c.size());
  }

  public boolean canProcessNext() {
    return (this.elementCount.decrementAndGet() >= 0);
  }
}
使用此类,每个线程设置自己的私有计数器(线程A为0,线程B为大小为1),然后进行如下检查:

if (this.threadSyncer.canProcessNext()) {
  this.theTasks[this.myPosition].process();

  this.myPosition += 1;  // this line in thread A
  this.myPosition -= 1;  // this line in thread B
}

你是什么意思
如何读取同一个列表
?将列表的引用传递给两个线程?!线程是否编辑列表?停止的精度必须有多高?例如,如果线程在相交后读取多个项目,这是否不好?@ThijsSteel,没有线程仅从列表中读取。是的,在相交后读取项目是不好的相交。因此,目标是读取所有列表,但从不同的一端读取,而不穿插。+1表示“批处理”@Rogger296,假设您使用两个线程的原因是为了加快计算速度,那么线程在同步点之间所做的工作越多,您从使用多个线程中获得的好处就越大。初学者通常会沮丧地发现,设计拙劣的多线程计算——线程之间耦合太多——会导致n要比单线程版本慢。我在这里使用的列表将文件大小作为属性之一。并且根据该列表按降序排序。因此,从顶部读取的线程T1移动缓慢,因为它必须适应较重的文件,而线程T2移动得很快,因为它是从列表底部读取的,其中file大小非常低。我不能使用批处理,因为它将加载线程T1和大量文件。所以要求每次线程从列表中获取单个元素时。@Rogger296您可以让线程1以批处理大小1或2工作,让线程1以更大的批处理大小工作。您甚至可以在flyRequirement上调整批处理大小不是对列表进行分区,而是同时使用两个线程读取它。T1从顶部开始,T2从底部开始。列表按降序排序,因此T1读取重文件,T2读取小文件。