通过引用通过Thread Constructor分配的列表变量不起作用

时间:2013-06-20 05:39:40

标签: java multithreading collections

我正在通过其构造函数初始化我的一个Thread的类变量 我的服务类如下:

ProcessMediaThread pThread = new ProcessMediaThread(listMediaPath, mediaType);
pThread.start();  

其中 listMediaPath ArrayList<String>();个对象 在ProcessMediaThread类中:

public class ProcessMediaThread extends Thread 
{
    private List<String> absoluteMediaPath= new ArrayList<String>();
    private String mediaType;
    public ProcessMediaThread(List<String> absoluteMediaPathList, String mediaType) 
    {
       this.absoluteMediaPath = absoluteMediaPathList;
       this.mediaType= mediaType;
    }

我覆盖的run()方法:

@Override
public void run()
{   
    if(mediaType.equals(MediaType.PHOTO)) //<- mediaType value is retained..
    {       
        for(int i=0;i<absoluteMediaPath.size();i++) // <- here absoluteMediaPath is empty..!!
        {
         //... 
        }

我的一位朋友建议我在构造函数级别中使用不同的方法

this.absoluteMediaPath.addAll(absoluteMediaPathList);

哪个有效.. !!
任何人都可以建议问题出现在哪里以及addAll(Collection<? extends E> c);正在做什么?

1 个答案:

答案 0 :(得分:3)

如果您使用addAll,则会将列表内容复制到ProcessMediaThread中的单独集合中。这意味着从外部改变它不会影响它。例如,考虑:

ProcessMediaThread pThread = new ProcessMediaThread(listMediaPath, mediaType);
pThread.start(); 
listMediaPath.clear();

使用当前代码,您的新线程可能会看到一个空集合 - 或者它可能会看到一个包含数据的集合,然后突然被清除。这并不是一个好的情况。另外,ArrayList不是线程安全的,所以在一个线程中修改它并在另一个线程中读取它可能会导致问题。

当你创建一个私人副本(使用addAll)时,上面第三行的clear()将无效,因为它不影响同一个集合线程正在使用。

其他几点:

  • 我建议您单独实施Runnable而不是扩展Thread。然后,您可以将Runnable的实例传递给Thread构造函数;这样可以更好地分离“在新线程上运行任务的机制”和“要运行的任务”。
  • 除非您在循环中实际需要i,否则您可以使用:

    for (String mediaPath : absoluteMediaPath) {
        ...
    }
    
  • 调用addAll的替代方法是仅使用ArrayList(Collection)构造函数在构造函数中初始化您的集合。

所有这些在一起,我会把你的课程改为:

public class MediaProcessor implements Runnable {
    private final List<String> absoluteMediaPath;
    private final String mediaType;

    public MediaProcessor(List<String> absoluteMediaPathList, String mediaType) {
       this.absoluteMediaPath = new ArrayList(absoluteMediaPathList);
       this.mediaType = mediaType;
    }

    @Override
    public void run() {
        if (mediaType.equals(MediaType.PHOTO)) {
            for (String mediaPath : absoluteMediaPath) {
                ...
            }
        }
    }
}

...

Thread thread = new Thread(new MediaProcessor(listMediaPath, mediaType));
thread.start();