我正在通过其构造函数初始化我的一个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);
正在做什么?
答案 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();