为什么多线程版本的时间与单线程版本相同?

时间:2016-02-06 06:05:05

标签: java multithreading

我有以下工作队列实现,我用它来限制使用的线程数。我最初在队列中添加了许多Runnable对象,当我准备开始时,我运行“begin()”。此时我不再添加任何队列。

com.android.support:design:23.0.1

这是一个可运行的,用于跟踪工作队列中的所有作业何时完成:

public class WorkQueue {

    private final int nThreads;
    private final PoolWorker[] threads;
    private final LinkedList queue;
    Integer runCounter;
    boolean hasBegun;

    public WorkQueue(int nThreads) {
        runCounter = 0;
        this.nThreads = nThreads;
        queue = new LinkedList();
        threads = new PoolWorker[nThreads];
        hasBegun = false;

        for (int i = 0; i < nThreads; i++) {
            threads[i] = new PoolWorker();
            threads[i].start();
        }
    }

    public boolean isQueueEmpty() {
        synchronized (queue) {
            if (queue.isEmpty() && runCounter == 0) {
                return true;
            } else {
                return false;
            }
        }
    }

    public void begin() {
        hasBegun = true;
        synchronized (queue) {
            queue.notify();
        }
    }

    public void add(Runnable r) {
        if (!hasBegun) {
            synchronized (queue) {
                queue.addLast(r);
                runCounter++;
            }
        } else {
            System.out.println("has begun executing. Cannot add more jobs ");
        }
    }

    private class PoolWorker extends Thread {

        public void run() {
            Runnable r;

            while (true) {
                synchronized (queue) {
                    while (queue.isEmpty()) {
                        try {
                            queue.wait();
                        } catch (InterruptedException ignored) {
                        }
                    }

                    r = (Runnable) queue.removeFirst();
                }

                // If we don't catch RuntimeException, 
                // the pool could leak threads
                try {
                    r.run();
                    synchronized (runCounter) {
                        runCounter--;
                    }
                } catch (RuntimeException e) {
                    // You might want to log something here
                }
            }
        }
    }
}

这就是我使用它们的方式:

public class QueueWatcher implements Runnable {

    private Thread t;
    private String threadName;
    private WorkQueue wq;

    public QueueWatcher(WorkQueue wq) {
        this.threadName = "QueueWatcher";
        this.wq = wq;
    }

    @Override
    public void run() {
        while (true) {
            if (wq.isQueueEmpty()) {
                java.util.Date date = new java.util.Date();
                System.out.println("Finishing and quiting at:" + date.toString());
                System.exit(0);
                break;
            } else {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {
                    Logger.getLogger(PlaneGenerator.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    public void start() {
        wq.begin();

        System.out.println("Starting " + threadName);
        if (t == null) {
            t = new Thread(this, threadName);
            t.setDaemon(false);
            t.start();
        }
    }
}

但无论我使用多少线程,结果总是相同的 - 它总是需要大约1毫秒才能完成。这与我刚刚执行单线程版本时(当所有内容都在main()中运行时)大致相同。 如果我将wq设置为(1,2,3--9)线程,它总是在1m8s-1m10s之间。问题是什么 ?作业(someRunnable)彼此无关,不能相互阻挡。

编辑:每个runnable只读取文件系统中的一些图像文件,并在单独的目录中创建新文件。新目录最终包含大约400个输出文件。

编辑:似乎只有一个线程始终在工作。我做了以下更改:

我让Woolworker存储Id

Workqueue wq = new WorkQueue(9); //Get same results regardless of 1,2,3,8,9
QueueWatcher qw = new QueueWatcher(wq);

SomeRunnable1 sm1 = new SomeRunnable1();
SomeRunnable2 sm2 = new SomeRunnable2();
SomeRunnable3 sm3 = new SomeRunnable3();
SomeRunnable4 sm4 = new SomeRunnable4();
SomeRunnable5 sm5 = new SomeRunnable5();

wq.add(sm1);
wq.add(sm2);
wq.add(sm3);
wq.add(sm4);
wq.add(sm5);

qw.start();

在跑步之前,我打印了工人的身份。

    PoolWorker(int id){
        this.threadId = id;
    }

在创建池工作者时,在WorkQueue构造函数中我做了:

                System.out.println(this.threadId + " got new task");
                r.run();

但似乎只有线程0才有效,因为输出总是:

  

0获得新任务

1 个答案:

答案 0 :(得分:6)

使用queue.notifyAll()开始处理。

目前您正在使用queue.notify(),它只会唤醒一个线程。 (指出这一点的一个重要线索是当你提到只有一个线程正在运行时。)

此外,Integer runCounter上的同步没有按照您的想法执行 - runCounter++实际上每次都为Integer分配一个新值,因此您正在同步很多不同的Integer个对象。

另一方面,即使对于最优秀的程序员来说,使用原始线程和wait/notify范例也很复杂且容易出错 - 这就是为什么Java引入了java.util.concurrent package,它提供了线程安全的BlockingQueue实现和Executors用于轻松管理多线程应用程序。

相关问题