Java 为什么不';线程池中的所有线程是否都在处理我的排队任务?

Java 为什么不';线程池中的所有线程是否都在处理我的排队任务?,java,multithreading,synchronization,threadpool,Java,Multithreading,Synchronization,Threadpool,我编写了一个简单的Java程序来帮助使用线程和线程池来完成某些任务。在我的程序中,有类TheObject的对象必须对它们进行某种处理(在这种情况下,只是一个睡眠延迟并打印出它们的字段) object对象被放置在队列中,从队列中WorkerThreads绘制并处理它们 我创建了一个Manager类来初始化TheObjectss和WorkerThreads。当我运行它时,我得到了奇怪的输出;不是线程关闭工作,而是一个线程处理所有事情!为什么会这样?如何让线程共享工作负载 这是输出: --------

我编写了一个简单的Java程序来帮助使用线程和线程池来完成某些任务。在我的程序中,有类
TheObject
的对象必须对它们进行某种处理(在这种情况下,只是一个睡眠延迟并打印出它们的字段)

object
对象被放置在队列中,从队列中
WorkerThread
s绘制并处理它们

我创建了一个
Manager
类来初始化
TheObjects
s和
WorkerThread
s。当我运行它时,我得到了奇怪的输出;不是线程关闭工作,而是一个线程处理所有事情!为什么会这样?如何让线程共享工作负载

这是输出

--------------------------------------------
alfred   a   0
Thread-0
--------------------------------------------
bob   b   1
Thread-0
--------------------------------------------
carl   c   2
Thread-0
--------------------------------------------
dave   d   3
Thread-0
--------------------------------------------
earl   e   4
Thread-0
--------------------------------------------
fred   f   5
Thread-0
--------------------------------------------
greg   g   6
Thread-0
--------------------------------------------
harry   h   7
Thread-0
--------------------------------------------
izzie   i   8
Thread-0
--------------------------------------------
jim   j   9
Thread-0
--------------------------------------------
kyle   k   0
Thread-0
--------------------------------------------
Larry   L   1
Thread-1
--------------------------------------------
Michael   M   2
Thread-1
--------------------------------------------
Ned   N   3
Thread-0
--------------------------------------------
Olaf   O   4
Thread-0
--------------------------------------------
Peter   P   5
Thread-0
--------------------------------------------
Quincy   Q   6
Thread-0
--------------------------------------------
Raphael   R   7
Thread-0
--------------------------------------------
Sam   S   8
Thread-0
--------------------------------------------
Trixie   T   9
Thread-0

守则:

课程:

  • 经理
  • 对象
  • 对象队列
  • 工作线程
经理

public class Manager {

    public static void main(String[] args) throws InterruptedException {
        TheObjectQueue queue = new TheObjectQueue();
        //Create Objects
        int numberOfInitialObjects = 10;
        String[] arrayOfNames = {"alfred", "bob", "carl", "dave", "earl", "fred", "greg", "harry", "izzie", "jim"};
        //char[] arrayOfChars = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'};
        //int[] arrayOfNums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        for (int i = 0; i < numberOfInitialObjects; i++){
                TheObject anObject = new TheObject(arrayOfNames[i], arrayOfNames[i].charAt(0), i);
                queue.addToQueue(anObject);

        }

        int numberOfThreads = 2;
        for (int i = 0; i < numberOfThreads; i++){
            WorkerThread workerThread = new WorkerThread(queue);
            workerThread.start();
        }

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


        String[] arrayOfNames2 = {"kyle", "Larry", "Michael", "Ned", "Olaf", "Peter", "Quincy", "Raphael", "Sam", "Trixie"};
        for (int i = 0; i < numberOfInitialObjects; i++){
            TheObject anObject = new TheObject(arrayOfNames2[i], arrayOfNames2[i].charAt(0), i);
            queue.addToQueue(anObject);
        }

    }
}
对象队列

import java.util.LinkedList;

public class TheObjectQueue {

    private LinkedList<TheObject> objectQueue = null;

    public TheObjectQueue(){
        objectQueue = new LinkedList<TheObject>();
    }
    public LinkedList<TheObject> getQueue(){
        return objectQueue;
    }
    public void addToQueue(TheObject obj){
        synchronized (this) {
            objectQueue.addFirst(obj);
            this.notify();
        }

    }
    public TheObject removeFromQueue(){
        synchronized (this) {
            TheObject obj = objectQueue.removeLast();
            return obj;
        } 
    }
    public int getSize(){
        return objectQueue.size();
    }
    public boolean isEmpty(){
        return objectQueue.isEmpty();
    }
}

WorkerThread.run中(共享)队列上的同步只允许单个线程一次处理一个任务-其效果实际上是一个工作线程池!在这种情况下,线程0在获得锁的大部分时间“获胜”;同步锁获取是一种有效的方法

一个简单的修复方法是使用所需的线程安全构造从队列中获取任务,然后在同步部分之外处理任务。这允许工作人员同时处理假定为独立的任务

// e.g.
@Override
public void run() {
    while(true){
        TheObject objToDealWith; 
        synchronized (queue) {
            // Only synchronized on queue when fetching task
            objToDealWith = getTask(queue);
        }

        // Process task; independent of queue
        process(objToDealWith);
    }
}
由于其中一个线程将忙于处理任务,而另一个线程正在(或已经)获取队列上的锁,因此工作分配将“公平”。为什么如此困难? 只需使用java提供的

如果你是手写的,你就做错了

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Sample {

    public static void main(String[] args) {
//      configure here how many threads and other properties, the queue here is actually build in.
        ExecutorService executor = Executors.newCachedThreadPool();
        String[] arrayOfNames = { "alfred", "bob", "carl", "dave", "earl",
                "fred", "greg", "harry", "izzie", "jim" };
        for (int i = 0; i < arrayOfNames.length; i++) {
            TheObject anObject = new TheObject(arrayOfNames[i], arrayOfNames[i].charAt(0), i);
            MyRunnable runnalbe = new MyRunnable(anObject);
            executor.execute(runnalbe);
        }
        executor.shutdown()
    }

    static class MyRunnable implements Runnable {

        final TheObject anObject;

        MyRunnable(TheObject theObject) {
            this.anObject = theObject;
        }

        @Override
        public void run() {
            //TODO do work with anObject
        }

    }

    static class TheObject {
        private String someName;
        private char someChar;
        private int someNum;

        public TheObject(String someName, char someChar, int someNum) {
            this.someName = someName;
            this.someChar = someChar;
            this.someNum = someNum;
        }

        public String getSomeName() {
            return someName;
        }

        public char getSomeChar() {
            return someChar;
        }

        public int getSomeNum() {
            return someNum;
        }
    }
}
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
公共类样本{
公共静态void main(字符串[]args){
//在这里配置多少线程和其他属性,这里的队列实际上是内置的。
ExecutorService executor=Executors.newCachedThreadPool();
String[]arrayOfNames={“alfred”、“bob”、“carl”、“dave”、“earl”,
“弗雷德”、“格雷格”、“哈利”、“伊兹”、“吉姆”};
for(int i=0;i
为什么不使用ExecutorService?@Jarrod我看不出这是一个复制品。即使存在不同的工具来实现这一点,问题并不在于它们的使用。我正在重新打开。此行为的一个可能原因是
isEmpty()
未同步,因此除
thread-0
之外的所有其他工作线程始终将队列视为空。哦,不,你调用了
isEmpty
队列上保持锁定,所以
isEmpty()
应该按预期工作。你回答的是问题的哪一部分?最多,这应该是一个注释。全部。重新设计队列?不可能。重塑ExecutorService/ThreadPool?不,重新发明轮子?不,改造一个螺纹工厂?不,所以我的答案是:使用java提供的工具。=>如果您使用这些类,就不会有问题。然后向我们展示如何使用
ExecutorService
解决OP的问题。仅链接的答案是。@Zarathustra根据代码以及Include
user2864740
的答案,如果使用
ExecutorService
,是否缺少任何内容?
// e.g.
@Override
public void run() {
    while(true){
        TheObject objToDealWith; 
        synchronized (queue) {
            // Only synchronized on queue when fetching task
            objToDealWith = getTask(queue);
        }

        // Process task; independent of queue
        process(objToDealWith);
    }
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Sample {

    public static void main(String[] args) {
//      configure here how many threads and other properties, the queue here is actually build in.
        ExecutorService executor = Executors.newCachedThreadPool();
        String[] arrayOfNames = { "alfred", "bob", "carl", "dave", "earl",
                "fred", "greg", "harry", "izzie", "jim" };
        for (int i = 0; i < arrayOfNames.length; i++) {
            TheObject anObject = new TheObject(arrayOfNames[i], arrayOfNames[i].charAt(0), i);
            MyRunnable runnalbe = new MyRunnable(anObject);
            executor.execute(runnalbe);
        }
        executor.shutdown()
    }

    static class MyRunnable implements Runnable {

        final TheObject anObject;

        MyRunnable(TheObject theObject) {
            this.anObject = theObject;
        }

        @Override
        public void run() {
            //TODO do work with anObject
        }

    }

    static class TheObject {
        private String someName;
        private char someChar;
        private int someNum;

        public TheObject(String someName, char someChar, int someNum) {
            this.someName = someName;
            this.someChar = someChar;
            this.someNum = someNum;
        }

        public String getSomeName() {
            return someName;
        }

        public char getSomeChar() {
            return someChar;
        }

        public int getSomeNum() {
            return someNum;
        }
    }
}