Java 从线程访问类变量时出现问题

Java 从线程访问类变量时出现问题,java,multithreading,Java,Multithreading,下面的代码旨在将产品对象的arraylist作为输入,为每个产品旋转线程,并将产品添加到arraylist“products”中,检查产品imageproduct.imageURL可用性,删除没有图像的产品将产品从arraylist“products”中移除,并返回具有可用图像的产品的arraylist package com.catgen.thread; import java.util.ArrayList; import java.util.Iterator; import java.ut

下面的代码旨在将产品对象的arraylist作为输入,为每个产品旋转线程,并将产品添加到arraylist“products”中,检查产品imageproduct.imageURL可用性,删除没有图像的产品将产品从arraylist“products”中移除,并返回具有可用图像的产品的arraylist

package com.catgen.thread;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.catgen.Product;
import com.catgen.Utils;

public class ProductFilterThread extends Thread{

    private Product product;
    private List<Product> products = new ArrayList<Product>();

    public ProductFilterThread(){
    }

    public ProductFilterThread(Product product){
        this.product = product;
    }

    public synchronized void addProduct(Product product){
         System.out.println("Before add: "+getProducts().size());
         getProducts().add(product);
         System.out.println("After add: "+getProducts().size());
    }

    public synchronized void removeProduct(Product product){
         System.out.println("Before rem: "+getProducts().size());
         getProducts().remove(product);
         System.out.println("After rem: "+getProducts().size());
    }

    public synchronized List<Product> getProducts(){
        return this.products;
    }

    public synchronized void setProducts(List<Product> products){
        this.products = products;
    }

    public void run(){
        boolean imageExists = Utils.fileExists(this.product.ImageURL);
        if(!imageExists){
            System.out.println(this.product.ImageURL);
            removeProduct(this.product);
        }
    }

    public List<Product> getProductsWithImageOnly(List<Product> products){
        ProductFilterThread pft = null;
        try{
            List<ProductFilterThread> threads = new ArrayList<ProductFilterThread>();
            for(Product product: products){
                pft = new ProductFilterThread(product);
                addProduct(product);
                pft.start();
                threads.add(pft);
            }
            Iterator<ProductFilterThread> threadsIter = threads.iterator();
            while(threadsIter.hasNext()){
                ProductFilterThread thread = threadsIter.next();
                thread.join();
            }
        }catch(Exception e){
            e.printStackTrace();
        }
        System.out.println("Total returned products = "+getProducts().size());
        return getProducts();
    }
}
在这里,当从getProductsWithImageOnly中调用addProductproduct时,getProducts返回产品列表,但情况并非如此。当线程调用removeProduct方法时,不会返回任何产品,因为没有图像的产品永远不会被删除。因此,无论包含的产品是否具有图像,模块都会返回所有产品

这里有什么问题

提前谢谢。 James.

您正在创建一个新的ProductFilter,在循环的每个迭代中执行以下操作:

new ProductFilterThread(product);
每个ProductFilterThread都有自己的

private List<Product> products = new ArrayList<Product>();
您正在从其自己的产品实例中删除该产品

我建议您以不同的方式进行设计,可能会给出线程应该使用的产品列表,作为ProductFilterThread的参数:

但是我必须说,在使用这样的多线程时,您应该仔细考虑。您需要小心地同步对数据结构的访问。

如果希望所有筛选线程共享产品列表,则必须将其设置为静态。田里都是


另一句话-也许您应该重写产品的getter/setter方法,以导出一个不可修改的列表,并在新创建的列表中读取输入。否则,在这种多线程设计中,这可能会导致多个头痛问题--想象一下,另一个线程正在“获取”列表,并在过滤处于活动状态时对其进行修改。

将arraylist设为静态会与由另一个请求旋转的线程共享它,如您所说。每个请求的所有线程都应该有一个arraylist副本。但当涉及到线程时,我完全迷失在可变范围内。关于导出不可修改列表的观点,需要回调类操作才能从getProductsWithImageOnly中读取它,对吗?我来看看。谢谢,真神奇!但我注意到所花的时间明显缩短了。这可能是因为额外的参数吗?不,这很可能是由于数据结构上的开销和同步。为此,最好使用线程池,在其中运行的线程数量与机器上的内核数量大致相同。。。。还有,堆效率高吗?我真的不知道。取决于你的瓶颈是什么。你分析过它吗?深入到基本问题,我们如何使类内的所有线程都可以访问类变量?我认为这里可以有两个构造函数,一个带参数“products”,另一个带参数“product”。在第一次实例化该类时,我们可以传递'products'参数并将其设置为变量,并可供使用'product'参数旋转的所有其他线程访问,从而允许所有其他线程访问'products'变量。
private List<Product> products = new ArrayList<Product>();
removeProduct(this.product);
private List<Product> products;

public ProductFilterThread(List<Product> products) {
    this.products = products;
}