【问题标题】:Java Executors and per-thread (not per-work unit) objects?Java Executors 和每个线程(不是每个工作单元)对象?
【发布时间】:2012-09-10 00:52:00
【问题描述】:

我有一个任务可以从线程池设计模式中受益(许多小任务要并行执行)。我最初从头开始实现了一个简单的线程池,n 个 Runnables 都从同一个ConcurrentLinkedQueue 拉出工作单元,直到队列为空,然后终止。然后我决定“嘿,让我们试试 Java 中的 Executor,因为它可能比我天真的设计的系统经过更好的测试和更可靠。”问题:在我的实现中,每个线程一直持续到队列为空,使用一段时间(!queue.isEmpty()),并获得了自己的非线程安全对象实例,我们称之为SlowObject foo,构造起来很耗时。试图通过所有进入Executor 池的Runnables 时间效率低的对象的实例失败,因为它不是线程安全的。为每个Runnable 创建一个SlowObject 的新实例是不可取的,因为它们的构建成本很高。

有没有办法说“我们正在使用多少个线程?让我们为每个线程创建一个SlowObject,然后让 Runnables 检测我们正在使用的线程并查找要使用的正确对象?”这听起来很脆弱且容易失败——不过,我不确定我应该看什么设计模式。

【问题讨论】:

  • 看看ThreadLocal
  • 您确定不能快速复制SlowObject 吗?查找需要放入其中的数据是不是很慢,还是在拥有所有数据后构造对象很慢?
  • @coding.mof,写下你的意见作为答案。恕我直言,这是正确的答案。

标签: java thread-safety threadpool executor


【解决方案1】:

最好使用资源池。使用这样的东西:

public class SlowObjectPool {
    private static final int POOL_SIZE = 10;
    private BlockingQueue<SlowObject> slowObjectQueue = new ArrayBlockingQueue(POOL_SIZE);

    public SlowObjectPool() {
        for (int i = 0; i < POOL_SIZE; i++) {
            slowObjectQueue.put(new SlowObject());
        }
    }

    public SlowObject take() throws InterruptedException {
        return slowObjectQueue.take();
    }

    public void release(SlowObject slowObject) {
        // TODO You may want to log a warning if this is false
        slowObjectQueue.offer(slowObject);
    }
}

您可能也希望将其设为单例。然后在您的可运行文件中:

public class MyRunnable implements Runnable {

    private SlowObjectPool pool;

    public MyRunnable(SlowObjectPool pool) {
        this.pool = pool;
    }

    @Override
    public void run() {
        // The next line blocks until a SlowObject is available
        SomeObject someObject = null;
        try {
            someObject = pool.take()
            // Do something with someObject
        } catch (InterruptedException ex) {
            // Thread is being ended, allow to end
        } finally {
            if (someObject != null)
                pool.release(someObject);
        }
    }
}

这将在第一次创建池时一次性创建所有对象,而不是动态创建它们,这样您的任何可运行对象都不必等待 SomeObject 实例被创建。

【讨论】:

    【解决方案2】:

    Java 提供了ThreadLocal 变量的概念。
    您可以像这样在Runnable 中使用它。

     public class MyJob implements Runnable {
         private static final ThreadLocal < SlowObject > threadLocal = 
           new ThreadLocal < SlowObject > () {
             @Override protected SlowObject initialValue() {
               // construct and return your SlowObject 
             }
           };
    
         public void run() {
           // work with threadLocal.get()
         }
       }
    

    因此,对于运行 Runnable 的每个线程,只会创建一个 SlowObject 类的实例。

    【讨论】:

      猜你喜欢
      • 2014-12-10
      • 2019-04-21
      • 1970-01-01
      • 2021-07-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-03
      相关资源
      最近更新 更多