public class TestRunnable implements Runnable {
private Vector<String> test = new Vector<String>();
public TestRunnable(int max) {
for (int i = 0; i < max; i++) {
test.add(i + "");
}
} public void run() {
while (test.size() > 0) { System.out.println("read :" + test.firstElement()
+ " thread name :" + Thread.currentThread().getName());
test.removeElement(test.firstElement()); }
} public static void main(String args[]) {
TestRunnable rc = new TestRunnable(1000);
ExecutorService exec = Executors.newFixedThreadPool(5);
for (int i = 0; i < 3; i++) {
exec.execute(rc);
}
exec.shutdown();
}
}
请问while里面需要同步吗??不需要的话,就报错Exception in thread "pool-1-thread-2" java.util.NoSuchElementException
at java.util.Vector.firstElement(Vector.java:447)
at TestRunnable.run(TestRunnable.java:22)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:650)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:675)
at java.lang.Thread.run(Thread.java:595)
vector不是线程同步的吗?为什么会出现这种情况啊?

解决方案 »

  1.   

    答:
    1)while(..){..}需要synchronized。
    2)为什么呢?
    Vector()是线程同步的,但它只保证:size() ,firstElement(),removeElement()这三个方法你调用时肯定是线程安全的,但不能认为:整个while中代码是线程安全的。否则当然会抛出java.util.NoSuchElementException 异常。这个异常是如何产生出来的?分析如下:
    设Vector中只剩下一个元素了。这是:线程A首先运行到:while(test.size() > 0),此时条件成立(因为有一个元素),但是当线程A准备执行while中的第一条语句println()之前,CPU切换到线程B,此时线程B也开始执行while(test.size() > 0),此时条件也是成立的!线程B准备执行它的while中的第一条语句println()之前,CPU又被切换到线程A,此时线程A将它的while中语句全做完(此时Vector中已没有元素了),CPU又切换到线程B,线程B继续执行它的while中语句,当执行到test.firstElement() 时,由于Vector中已没有元素了,该方法将抛出:java.util.NoSuchElementException .
    因此:按你现在的run()代码来说,你必须将整个while进行同步化,目的是:当线程A进行while时,CPU不能切换到竞争对手线程B中.后果:如果整个while同步化,则整个程序的并发多线程的优势大大地削减了.
    以上仅供你参考
      

  2.   

    public class TestRunnable implements Runnable {
    private Vector<String> test = new Vector<String>();
    Lock lock = new ReentrantLock(); public TestRunnable(int max) {
    for (int i = 0; i < max; i++) {
    test.add(i + "");
    }
    } public void run() {
    while (test.size() > 0) {
    lock.lock();
    System.out.println("read :" + test.firstElement()
    + " thread name :" + Thread.currentThread().getName());
    test.removeElement(test.firstElement());
    lock.unlock();
    }
    } public static void main(String args[]) {
    TestRunnable rc = new TestRunnable(1000);
    ExecutorService exec = Executors.newFixedThreadPool(5);
    for (int i = 0; i < 3; i++) {
    exec.execute(rc);
    }
    exec.shutdown();
    }
    }谢谢,不过我这样加锁还是不行
    read :833 thread name :pool-1-thread-3
    read :834 thread name :pool-1-thread-3
    read :835 thread name :pool-1-thread-3
    read :836 tException in thread "pool-1-thread-1" java.util.NoSuchElementException
    at java.util.Vector.firstElement(Vector.java:447)
    at TestRunnable.run(TestRunnable.java:20)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:650)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:675)
    at java.lang.Thread.run(Thread.java:595)
    hread name :pool-1-thread-3
    read :837 thread name :pool-1-thread-3
    read :838 thread name :pool-1-thread-3
    read :839 thread name :pool-1-thread-3
    read :840 thread name :pool-1-thread-3
    read :841 thread name :pool-1-thread-3
    read :842 thread name :pool-1-thread-3
    read :843 thread name :pool-1-thread-3
    read :844 thread name :pool-1-thread-3只能同步整个while方法吗?
      

  3.   

    答:这样加锁当然不行啊.你得将:条件检测test.size() > 0的while(...)加进去啊.否则是一样的后果啊.
      

  4.   

    请问下,又没有别的方法,不同步整个while语句?我尝试test.removeElement(test.firstElement()); 语句后面加Thread.currentThread().sleep(10);或者synchronized(this){
    if(test.size() > 0)
    test.removeElement(test.firstElement());
    }
    这样好像处理的不是很适当吧?
      

  5.   

    答:要仔细考虑一下.我的初步想法是:如果不同步整个while,则只能在firstElement())及removeElement()方法时,用test.size()先判.就像你写的那个代码.但要注意:synchronized(this){ 
    if(test.size() > 0) 中的this应该是其它线程都共享的一个对象,像现在这样的this,指当前你的线程,肯定是不行的.