解决方案 »

  1.   

    这和等待放在哪里没有关系
    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }这几行代码完全可以删除。程序的意思是:两个人同时操作一个list(先判断不为空,然后删除第一个元素)。多线程操作可能出现以下特殊情况:当list只剩最后一个时,Person1先判断list不为空,然后线程跳转,Person2判断list也不为空,于是删除第一个元素,此时,线程跳转回去,Person1之前判断过不为空了,于是直接执行remove操作,但list已经没有数据了,所以报错
      

  2.   

    原因在于:如果线程一正好等待,但是这个时候,list中恰好有一个还没删除,而这时线程二获得了执行权限,因为线程一还在等待,没有删除,所以!list.isEmpty()为true,线程二可以进入循环,那么线程二开始等待,接下来,线程一等待结束,开始执行删除操作,等线程二执行删除操作的时候,list已经空了,所以会报下标越界异常,这个问题要解决的办法是加同步锁,或者加入判断。
    其实这样子的操作是模拟一个卖火车票的那种情况。
      

  3.   

    class Person extends Thread{
        List<String> list;
        //本方法中,run将被并发调用
        public void run(){
            Thread t=Thread.currentThread();
             //假设集合有2个元素
                while(!list.isEmpty()){// a , b  进来
                    
                    try {
                        Thread.sleep(100);// a, 停下了 , b 随后也停下
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    
                    String one=list.remove(0);//a 执行完了出去了.....  (假设b还没醒)然后 a 又进 while 条件了, b 没醒就没执行 remove , b 执行了删除了集合中最后一个,然后 a 又继续删除,然后出问题了
            
                    System.out.println(t.getName()+one);
                }
                if(list.isEmpty()){
                    System.out.println("卖完了!");
                }
             
        }
      

  4.   

    class Person extends Thread{
        List<String> list;
        //本方法中,run将被并发调用
        public void run(){
            Thread t=Thread.currentThread();
                //假设集合有2个元素 , 
                while(!list.isEmpty()){// a,b 线程进来了 , b 在这里停下了,
                    String one=list.remove(0); //a 线程执行了 , 
                    try {
                        Thread.sleep(100); //a 停下了,  a 执行完又出去了,接着a  进 while,然后因为b没醒,a 执行了,b 突然醒了,然后 a , b 都要 remove 集合中元素,但是集合中只有一个元素,故也会出现异常;
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    System.out.println(t.getName()+one);
                }
                if(list.isEmpty()){
                    System.out.println("卖完了!");
                }
             
        }
      

  5.   

    [初学回复总结]: 感觉2个线程最好分析, 多个线程情况多,有点难分析; 多线程最难的地方就是,多线程并不是同时执行的,也就是说,
    同一时段一段代码只能有一个线程在跑; 这个也是晕多线程的原因; 你的第二个一进来就 remove (0) 不会出现问题,那是因为可能 执行太快了,不容易看到错误,最后做一个总结: 两个以上的线程操作同一共享资源避免安全隐患必须使用锁(同步代码块 | jdk1.5 锁的新特性);
      

  6.   

    ArralyList这个类不是线程安全的,不能作为多线程的共享集合对象进行访问。
    所以,出现数组下标越界,也是很正常的事情。
      

  7.   

    当集合里面只有一个元素的时候,两个线程同时过isEmpty方法,返回相同的boolean值,
    这时,可能产生一种情况,并发情况下,有可能一个线程先执行了后续的代码,删除了集合内的元素,
    另一个线程后执行后续的代码,仍然要删除集合内的元素,由于集合对象不是线程安全的,并且当前环境中,也米有对象可删,
    就会抛出异常了。
    明白了? 
    单个线程不会出这个问题,因为,在一个线程内,调用isEmpty方法后,如果集合里面有对象,那么,后续的代码执行时,它就是有对象的,并且,除了这个线程以外,是没有其他线程会对这个集合进行内容的更改的。
      

  8.   

    1.这个问题与操作对象是否为线程安全无关(Vector也会报错)
    2.除了【1】,楼上说的是正解
      

  9.   

    Vector所谓的线程安全是指调用Vector类的成员方法时,其他线程不能再访问该Vector对象。但是在调用两个Vector成员方法时,当前线程有可能再完成第一个方法后时间片到期,这时其他线程可以访问该Vector对象,造成调用第二个成员方法的结果可能与预想结果不同。这时为保证线程安全,需要加synchronized。
      

  10.   

    package day0611;import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    import java.util.Vector;public class Yesterday {
    public static void main(String[] args) {
    Vector<String> list = new Vector<String>(); //
    list.add("肉包子");
    list.add("菜包子");
    list.add("狗不理");
    list.add("豆沙包");
    list.add("汉堡包");
    list.add("汉堡包2");
    list.add("汉堡包3");
    list.add("汉堡包4");
    list.add("汉堡包5");
    list.add("汉堡包6");
    list.add("汉堡包7");
    list.add("汉堡包8");
    list.add("汉堡包9");
    Object lock = new Object(); Person p1 = new Person(list, lock);
    Person p2 = new Person(list, lock); // 两个对象共享同个资源
    p1.start();
    p2.start();
    }
    }class Person extends Thread {
    private Vector<String> list;
    private Object lock; Person(Vector<String> list, Object lock) {
    this.list = list;
    this.lock = lock;
    } // 本方法中,run将被并发调用
    public void run() {
    while (true) {
    synchronized (lock) { if (!list.isEmpty()) {
    try {
    Thread.sleep(100);
    } catch (InterruptedException e) {
    e.printStackTrace();
    } String one = list.remove(0);
    System.out.println(Thread.currentThread().getName() + ":"
    + one);
    }//if
    }
    }//while
    }//run
    }
    //实际上不使用Vector ,线程同步安全的 list ,应该使用集合工具类来转换一个线程安全的list; vector 不能真正解决线程安全,没有效率并且需要同步代码块
      

  11.   

    Person类加锁,这样写class Person extends Thread {
    List<String> list;
    public void run() {
    Thread t = Thread.currentThread();
    while (true) {
    synchronized (list) {
    if (!list.isEmpty()) {
    try {
    Thread.sleep(100);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    String one = list.remove(0);
    System.out.println(t.getName() + one);
    } else {
    System.out.println("卖完了");
    break;
    }
    }
    }
    }
    }