【问题标题】:Issue accessing class variable from thread问题从线程访问类变量
【发布时间】:2010-06-14 07:40:54
【问题描述】:

下面的代码旨在将产品对象的arraylist作为输入,为每个产品旋转线程(并将产品添加到arraylist'products'),检查产品图像(product.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();
    }
}

调用语句:

displayProducts = new ProductFilterThread().getProductsWithImageOnly(displayProducts);

这里,当从 getProductsWithImageOnly() 中调用 addProduct(product) 时,getProducts() 返回产品列表,但当线程调用方法 removeProduct() 时,情况并非如此(不返回任何产品),因此,没有图像的产品永远不会被删除。结果,无论包含的产品是否有图像,模块都会返回所有产品。

这可能是什么问题?

提前致谢。 詹姆斯。

【问题讨论】:

    标签: java multithreading


    【解决方案1】:

    您正在循环中的每次迭代创建一个新的ProductFilterThread

    new ProductFilterThread(product);
    

    每个ProductFilterThread 都有自己的

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

    所以当你在 run 方法中,做

    removeProduct(this.product);
    

    您正在从它自己的 products 实例中删除产品。

    我建议您以不同的方式设计它,也许可以提供线程应该使用的产品列表,作为ProductFilterThread 的参数:

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

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

    【讨论】:

    • 谢谢,这很神奇!但我注意到所花费的时间显着增加。可能是因为额外的参数?
    • 不,这很可能是由于数据结构的开销和同步。为此,您最好使用线程池,在其中您运行的线程数量与机器上的内核数量大致相同。
    • ... 而且,它是堆高效的吗?
    • 真的不知道。取决于你的瓶颈是什么。你分析过它吗?
    • 从基础开始,我们如何使类变量可供从类中旋转的所有线程访问?我认为我们可以在这里有两个构造函数,一个带有参数“products”,另一个带有“product”。在第一次实例化类时,我们可以传递 'products' 参数并将其设置为变量,并且所有其他使用 'product' 参数的线程都可以访问,从而允许所有其他线程访问 'products'变量。
    【解决方案2】:

    如果您希望 products 列表被所有过滤线程共享,那么您必须将其设为静态。字段为confined to a single thread

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

    【讨论】:

    • 如您所说,将 arraylist 设为静态将与另一个请求旋转的线程共享它。每个请求(的所有线程)都应该有一个数组列表的副本。但是当涉及到线程时,我完全迷失在可变范围内。关于导出不可修改列表的观点,这需要回调(某种操作)才能从 getProductsWithImageOnly() 中读取它,对吗?我会检查一下。
    猜你喜欢
    • 1970-01-01
    • 2015-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-03
    • 1970-01-01
    相关资源
    最近更新 更多