日期:2014-05-20  浏览次数:20714 次

一个简单的java多线程问题


public class Begin {
    public static void main(String[] args) {
        Image image = new Image();
        List<String> list = new ArrayList<String>();
        list.add("1.jpg");
        list.add("5.jpg");
        list.add("2.jpg");
        list.add("7.jpg");
        list.add("6.jpg");
        list.add("9.jpg");
        image.setUrls(list);
        for (int i = 0; i < 3; i++) {
            ImageDFile imageDFile = new ImageDFile(image);
            imageDFile.start();
        }
    }
}

ImageDFile类

public class ImageDFile extends Thread {
    public Image image;
    public ImageDFile(Image image) {
        this.image = image;
    }

    @Override
    public void run() {
        List<String> list = image.getUrls();
        for (int i = 0; i < list.size(); i++) {
            if (list.size() > 0) {
                System.out.println(list.get(i) + "---" + Thread.currentThread().getName());
                list.remove(i);
            }
        }
    }
}

Image类就一个属性 private List<String> urls

运行的时候时不时的报错

Exception in thread "Thread-0" java.lang.IndexOutOfBoundsException: Index: 1, Size: 1

知道肯定是多线程导致的,不知道synchronized应该加在什么位置?可否详细讲下

------解决方案--------------------
List线程不安全导致,你想要得到什么样的效果
------解决方案--------------------
 觉得是 list.remove(i); 的问题,你可以先注释掉看程序可以不   
------解决方案--------------------
是remove的问题,但是并非是指通常意义的遍历时Remove报错。
所谓的遍历时报错,是指先吧List装到一个Iterator中, 然后这边用Iterator.next遍历,那边用List.remove时出错。

另外,我觉得LZ的遍历代码和Remove代码有很大的问题 -- 一般来说,我觉得这个遍历时希望各个线程能尽可能快的抓List的第1个img,如果抓到了就把它排除出去。

不过即便是单线程,LZ的代码也是达不到这个目的的。
假设有List中有10个img,分别是000,001,002,...,009,通常,对于单线程来讲,希望它的输出结果就是000,001,002,...,009.
不过模拟一下就可以发现,第一个输出元素是item[0],即000不假,不过此后由于Remove语句,所以List变成了[001,002,003,...,009],然后i=1,结果下一个输出是002。
再接下去是004,006,008

此外,线程的 判断数据存在+显示数据+删除数据 应当加上同步锁,否则当判断数据时有数据存在,当显示数据时系统发现该数据已经被其它线程删除了,自然会报IndexOutofRange错误。

是我的话,线程代码可能会改成

  public void run() {
         List<String> list = image.getUrls();
         for (; list.size()>0;) {
         synchronized(this){
             if (list.size() > 0) {
                 System.out.println(list.get(0) + "---" + Thread.currentThread().getName());
                 list.remove(0);
             }
         }
         }
     }

------解决方案--------------------

public class ImageDFile extends Thread {
    public Image image;
    public ImageDFile(Image image) {
        this.image = image;
    }

    @Override
    public void run() {
     synchronized (image) { // 在此处添加synchronized关键字即可
     List<String> list = image.getUrls();
            for (int i = 0; i < list.size(); i++) {
                if (list.size() > 0) {
                    System.out.println(list.get(i) + "---" + Thread.currentThread().getName());