多个相同任务的Java线程池

多个相同任务的Java线程池,java,multithreading,threadpool,Java,Multithreading,Threadpool,我有一个线程,唯一的工作就是从套接字中抓取数据包,并将它们放入缓冲区。另一个线程使用该缓冲区,处理数据包。我希望有一个线程池使用该缓冲区 我曾想过使用一个固定的线程池来实现这一点。为此,我是否需要创建池,然后提交足够的可运行文件以供执行以填充池?我曾希望有一种方式可以说“这是我希望您执行的线程/可运行线程,这是我希望运行的线程数,开始!”。有这样的方法吗?除了固定线程池之外,其他的东西更合适吗?由创建的固定线程池可以正常工作 实现的内部语义是这样的,线程池将优先创建新线程,直到它达到您想要的首选

我有一个线程,唯一的工作就是从套接字中抓取数据包,并将它们放入缓冲区。另一个线程使用该缓冲区,处理数据包。我希望有一个线程池使用该缓冲区


我曾想过使用一个固定的线程池来实现这一点。为此,我是否需要创建池,然后提交足够的可运行文件以供执行以填充池?我曾希望有一种方式可以说“这是我希望您执行的线程/可运行线程,这是我希望运行的线程数,开始!”。有这样的方法吗?除了固定线程池之外,其他的东西更合适吗?

由创建的固定线程池可以正常工作


实现的内部语义是这样的,线程池将优先创建新线程,直到它达到您想要的首选大小(核心池大小)。

由创建的固定线程池可以正常工作


实现的内部语义是这样的,线程池将优先创建新线程,直到它达到其首选大小(核心池大小),这似乎正是您想要的。

当您使用
ExecutorService
时,您将
Runnable
作业提交到线程池中,线程池中的线程依次运行这些作业。您可以执行以下操作之一:

  • 让每个
    Runnable
    坐在一个循环中,从
    BlockingQueue
    循环中退出队列以处理每个数据包。这可能比围绕缓冲区对象进行同步要容易。比如:

    public void run() {
       while (!shutdown) {
          packet = packetQueue.take();
          processPacket(packet);
       }
    }
    
    Payload payload;
    public void run() {
       // process packet here
       processPayload(payload);
    }
    
  • 或者,您可以将每个数据包作为作业本身提交到线程池,尽管这可能会增加对象负载。您可以处理每个数据包,提取负载,并使用处理负载的
    run()
    方法在负载周围创建一个
    Runnable
    包装器。
    Runnable
    类的内容如下:

    public void run() {
       while (!shutdown) {
          packet = packetQueue.take();
          processPacket(packet);
       }
    }
    
    Payload payload;
    public void run() {
       // process packet here
       processPayload(payload);
    }
    
  • 对于这两种机制,我会选择一个与处理器数量和处理任务性质最匹配的固定线程数。下面的示例使用了处理器的数量,但您可能希望为GC或其他任务减少一些处理器。您可能希望在其他IO上增加更多的处理块。只有性能测试才能告诉您最佳值是多少

    // start a pool that uses the number of threads that there are processors
    ExecutorService threadPool = Executors.newFixedThreadPool(
        Runtime.getRuntime().availableProcessors());
    

    使用
    ExecutorService
    时,将
    Runnable
    作业提交到线程池中,线程池中的线程依次运行这些作业。您可以执行以下操作之一:

  • 让每个
    Runnable
    坐在一个循环中,从
    BlockingQueue
    循环中退出队列以处理每个数据包。这可能比围绕缓冲区对象进行同步要容易。比如:

    public void run() {
       while (!shutdown) {
          packet = packetQueue.take();
          processPacket(packet);
       }
    }
    
    Payload payload;
    public void run() {
       // process packet here
       processPayload(payload);
    }
    
  • 或者,您可以将每个数据包作为作业本身提交到线程池,尽管这可能会增加对象负载。您可以处理每个数据包,提取负载,并使用处理负载的
    run()
    方法在负载周围创建一个
    Runnable
    包装器。
    Runnable
    类的内容如下:

    public void run() {
       while (!shutdown) {
          packet = packetQueue.take();
          processPacket(packet);
       }
    }
    
    Payload payload;
    public void run() {
       // process packet here
       processPayload(payload);
    }
    
  • 对于这两种机制,我会选择一个与处理器数量和处理任务性质最匹配的固定线程数。下面的示例使用了处理器的数量,但您可能希望为GC或其他任务减少一些处理器。您可能希望在其他IO上增加更多的处理块。只有性能测试才能告诉您最佳值是多少

    // start a pool that uses the number of threads that there are processors
    ExecutorService threadPool = Executors.newFixedThreadPool(
        Runtime.getRuntime().availableProcessors());
    

    #1似乎与线程池的精神相反——将工作单元分配到最多N个线程的池中。相反,您正在旋转所有N个线程(其中N=最大池大小),每个线程都坐在队列上等待工作到来。如果采用这种方式,您还可以直接创建N个线程,并完全跳过线程池。还有一件事——如前所述,#1的关闭策略不太有效,因为线程可能会在数据包队列上永远等待,并且永远不会重新检查“关闭”并终止。在这种情况下,我通常使用“毒丸”方法来表示线程应该终止。实际上,任何需要线程的任务都可以通过线程池@Jim来改进。即使在情况#1.当您在线程池上发出一个
    shutdownNow()
    时,该线程将
    中断()
    每个线程,从而导致
    线程
    抛出一个
    中断异常
    。通常我就是这么做的。“毒丸”也能起作用。打断别人的话很有道理。。。只要对runnable进行编码以正确处理中断。有时这是不可能保证的,特别是当您调用可能执行阻塞操作的第三方代码时。#1似乎与线程池的精神背道而驰——将工作单元分配到最多N个线程的池中。相反,您正在旋转所有N个线程(其中N=最大池大小),每个线程都坐在队列上等待工作到来。如果采用这种方式,您还可以直接创建N个线程,并完全跳过线程池。还有一件事——如前所述,#1的关闭策略不太有效,因为线程可能会在数据包队列上永远等待,并且永远不会重新检查“关闭”并终止。在这种情况下,我通常使用“毒丸”方法来表示线程应该终止。实际上,任何需要线程的任务都可以通过线程池@Jim来改进。即使在情况#1.当您在线程池上发出一个
    shutdownNow()
    时,该线程将
    中断()
    每个线程,从而导致
    线程
    抛出一个
    中断异常
    。通常我就是这么做的。“毒丸”也能起作用。打断别人的话很有道理。。。只要对runnable进行编码以正确处理中断。有时这是不可能保证的,尤其是