2010-06-14 6 views
0

아래 코드는 제품 객체의 arraylist를 각 제품의 입력, 회전 스레드로 가져오고 (arraylist '제품'에 제품을 추가), 제품 이미지 (product.imageURL) 가용성, 이미지없이 제품을 제거 (arraylist '제품'에서 제품을 제거), 그리고 이미지 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(); 
    } 
} 

호출 문 : addProduct (제품) getProductsWithImageOnly() 내에서 호출 여기

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

, getProducts()는 제품 목록을 반환하지만 그 경우 (제품이 없습니다 아니다 리턴 된) 메소드가 removeProduct() 메소드를 스레드에 의해 호출 될 때, 이미지가없는 제품이 절대로 제거되지 않기 때문입니다. 따라서 포함 된 제품에 이미지가 있는지 여부에 관계없이 모든 제품이 모듈에 의해 반환됩니다.

여기에서 문제가 될 수있는 것은 무엇입니까?

미리 감사드립니다. James, James.

답변

0

당신은 루프에서 새로운 ProductFilterThread 각 반복 만드는 :

new ProductFilterThread(product); 

ProductFilterThread은이를 자신의 당신의 run 방법으로 수행 그래서

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

removeProduct(this.product); 

당신은 자신의 제품을 제거하려는 겁니다 products 인스턴스.

private List<Product> products; 

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

을하지만 여러 작업을 할 때 당신이주의 깊게 생각해야한다고 말을해야 :

난 당신이 아마 ProductFilterThread에 인수로, 스레드가 작동해야하는 제품 목록을 제공하여, 다르게 설계 제안 이런 스레드. 데이터 구조에 대한 액세스를 신중하게 동기화해야합니다.

+0

감사합니다. 그러나 나는 걸리는 시간이 엄청나게 걸렸다는 것을 알아 차렸다. 추가 매개 변수 때문일 수 있습니까? – James

+0

아니요, 데이터 구조의 오버 헤드와 동기화로 인해 발생했을 가능성이 큽니다. 스레드 풀을 사용하면 스레드 풀을 사용하는 것이 더 좋을 것입니다. 스레드 풀은 컴퓨터에 코어를 가지고있는 것처럼 대략 많은 스레드를 실행합니다. – aioobe

+0

... 그리고 힙이 효율적입니까? – James

0

products 목록을 모든 필터 스레드에서 공유하려는 경우 정적으로 만들어야합니다. 필드는 confined to a single thread입니다.

또 다른 의견 - 수정 가능 목록을 내보내고 새로 만든 목록에서 입력을 읽으려면 products에 대한 getter/setter 메서드를 다시 작성해야합니다. 그렇지 않으면이 멀티 스레드 디자인에서 여러 골칫거리의 원인이 될 수 있습니다. (필터링을 활성화하는 동안 다른 스레드가 목록을 가져 와서 수정하는 것을 상상해보십시오)

+1

arraylist를 정적으로 만들면 말했듯이 다른 요청에 의해 회전 된 스레드와 공유하게됩니다. 각 요청 (모든 스레드)에 대해 arraylist의 복사본이 하나 있어야합니다. 하지만 스레드와 관련해서는 여기서 변수 범위를 완전히 잃어 버렸습니다. 수정할 수없는 목록을 내보낼 때의 포인트에 대해 getProductsWithImageOnly() 내에서 읽으려면 콜백 (동작 종류)이 필요합니다. 나는 그것을 체크 할 것이다. – James

관련 문제