Java 从线程访问类变量时出现问题
下面的代码旨在将产品对象的arraylist作为输入,为每个产品旋转线程,并将产品添加到arraylist“products”中,检查产品imageproduct.imageURL可用性,删除没有图像的产品将产品从arraylist“products”中移除,并返回具有可用图像的产品的arraylistJava 从线程访问类变量时出现问题,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
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;
}