0

有没有一种优雅的方式来做到这一点?或者它总是可以避免,因为可以使用更好的设计模式?

import java.util.ArrayList;
import java.util.List;

public class ForTest {

    List<String> ls = new ArrayList<String>();

    public static void main(String[] args) {
        ForTest forTest=new ForTest();
        System.out.println(forTest.ls.size());

        new Thread(new Worker(forTest.ls)).start();
        //size() does not change at all
        System.out.println(forTest.ls.size());
    }
}

class Worker implements Runnable{
    List<String> list;
    public Worker(List<String> li) {
        this.list = li;
    }

    public void run(){
        this.list.add("newItem");
    }
}
4

5 回答 5

2

您的代码存在几个问题(特别是您使用 ArrayList,如果没有适当的同步,它就不是线程安全的)。

但最明显的一点是第二个 println 语句几乎总是会在您的方法有机会执行之前被调用。run

于 2013-07-31T14:35:46.067 回答
2

你需要让你的线程sleep()一段时间。在新的有机会更新它size()之前被调用。Thread

new Thread(new Worker(forTest.ls)).start();

Thread.sleep(2000);
System.out.println(forTest.ls.size());

更好的方法是进入join()工作线程。这将使主线程在工作人员完成时自动唤醒。

Thread worker = new Thread(new Worker(forTest.ls));

worker.start();
worker.join();
System.out.println(forTest.ls.size());

除此之外,如果列表将由多个线程共享和修改,则使用同步 ArrayList来防止竞争条件。

List<String> ls = Collections.synchronizedList(new ArrayList<String>());
于 2013-07-31T14:42:26.393 回答
1

你似乎错过了线程的想法。您的代码将不起作用,因为您的工作人员在您打印时可能尚未更新 ls 。如果您使用线程,则线程需要通信状态。这一切都很复杂,我建议您阅读有关线程http://docs.oracle.com/javase/tutorial/essential/concurrency/的 java 教程

于 2013-07-31T14:37:04.687 回答
1

请注意,ArrayList不是同步的,而是同步Vector的。你不能指望工人在你启动它的线程后立即运行。这就是列表大小尚未更改的原因。我想这不是您的完整示例,因此很难为您提供帮助。(如果这是您的完整示例,我想知道您为什么要费心实施多线程解决方案。)
要知道工作人员何时完成,您可以加入线程

于 2013-07-31T14:43:18.817 回答
1

等待新线程实际开始运行您的代码 + make forTestfinal 以便能够访问它(也使用线程安全集合 - 最好的非同步又名非阻塞)例如

import java.util.Collection;
import java.util.concurrent.ConcurrentLinkedQueue;

public class ForTest {

    Collection<String> ls = new ConcurrentLinkedQueue<String>();

    public static void main(String[] args) throws InterruptedException {
        final ForTest forTest = new ForTest();

        System.out.println(forTest.ls.size());

        int threads = 10;

        for ( int i=0; i<threads; i++ ) {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    forTest.ls.add("newItem");
                }

            }).start();
        }

        Thread.sleep(1000);// wait for it !

        System.out.println(forTest.ls.size()); // 10 unless your threads are really slow
    }

}
于 2013-07-31T14:46:46.097 回答