我正在try 使用自定义ThreadFactory实现,它允许我使用自定义对象而不是通用Runnable对象.

以下是我所能提供的最小例子.除了为我的问题创建一个功能框架之外,Foo()类定义和Main()在很大程度上无关紧要.我正在使用ExecutorServiceexecute()方法来调用我的ExampleFactory.这个问题很大程度上与通过ExecutorService调用过载的ThreadFactory的正确利用有关.代码后面的上下文.

import java.lang.Runnable;
import java.util.concurrent.ThreadFactory

class ExampleFactory implements ThreadFactory{
    public Thread newThread(Foo f){
        String threadName = "ID: " + f.getID();
        return new Thread(f, threadName);
    }
    
    @Override
    public Thread newThread(Runnable r){
        if (! (r instanceof Foo)) {
            throw new IllegalArugmentException("Not Foo");
        }
        
        return new Thread(r, "Boo"); //won't get here, thrown exception
    }
}
...
import java.lang.Runnable;


public class Foo implements Runnable{
    
    public int ID = 0; 
    
    public Foo(int i){
        this.ID = i;
    }
    
    public int getID(){
        return this.ID;
    }
    
    @Override
    public void run() {
        System.out.println("Running (Runnable): " + this.ID);
    }
}
...
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {
    public static void main(String[] args) {
        ExecutorService e = Executors.newFixedThreadPool(10, new ExampleFactory());
        
        for (int i = 0; i < 100; i++){
            Foo f = new Foo( i );
            System.out.println("Executing i: "+ i);
            e.execute(f);   
      }
    }
}

当使用ExecutorService时,我不会看到调用newThread(Foo f),而是调用newThread(Runnable r).

有更好的方法吗?

我希望能够在线程工厂中调用Foo中的getter方法,以在.start()之前进行标记和其他目的.

发生这种情况似乎是因为ExecutorServiceexecute()方法期望一个Runnable对象,并且通过调用.execute(),我正在铸造Foo - Runnable.鉴于我使用的是ThreadFactory,我预计首先调用ExampleFactory,然后execute()将接收返回的对象.

我可以超载Executor Service的execute(Runnable)方法以获得类似的execute(Foo f),但对于这个问题来说这似乎有些矫枉过正吗?特别是因为我只会更改输入和返回类型,但会保留以前的功能?

推荐答案

如果您在ExampleFactory.newThread中放置调试断点,您会看到ThreadPoolExecutor正在将Foo实例包装在内部私有Worker对象(其本身实现Runnable)中. 源代码说明了这样做的原因:

Class Worker主要维护运行任务的线程的中断控制状态,以及其他小簿记.此类机会性地扩展了AbstractRoutizer,以简化获取和释放围绕每个任务执行的锁.这可以防止旨在唤醒等待任务的工作线程而不是中断正在运行的任务的中断.我们实现一个简单的不可重入互排锁,而不是使用ReentrantLock,因为我们不希望worker任务在调用setCorePoolSize等池控制方法时能够重新获取锁.此外,为了在线程实际开始运行任务之前 suppress 中断,我们将锁状态初始化为负值,并在启动时清除它(在runWorker中).

Worker对象已关闭访问,因此您无法访问下级委托.

退后一步:

我认为您混淆了RunnableThread的生命周期. 在长时间运行的Java中,您将有少量Thread,这些Thread通常是长生命周期 的,并为典型应用程序中的许多Runnable/Callable实例提供服务(也许不是您的). 因此,以它处理的first Foo命名您的线程似乎不正确. (线程创建/销毁成本很高,这就是为什么Javascript会让线程池等待工作.)

假设您想做的是label线程,以向观察者指示它根据当前工作正在做什么;如果这只是您想做的事情(我看到您说的是"标记和其他目的"),您可以更简单地调用Thread.setName(..)一旦您运行线程.

    @Override
    public void run() {
        Thread.currentThread().setName("ID: " + this.getID());
        System.out.println("Running (Runnable): " + this.ID);
    }

我以前try 过这种方法,监控工具并不期望线程的名称不断变化,所以通过这种方式您可能无法实现您想要的目标.

你说"和其他目的". 好吧,也许你应该往不同的方向看.查看ThreadPoolExecutor的子分类并实现beforeExecute(Thread t, Runnable r),因为这可能会提供您想要的东西:

在给定线程中执行给定Runnable之前调用的方法.此方法由执行任务r的线程t调用,并且可以用于重新初始化ThreadLocalals或执行日志(log)记录.

Java相关问答推荐

在Spring Boot中测试时出现SQL语法错误

如何为具有多对多关系的实体的给定SQL查询构建JPA规范?

S的字符串表示是双重精确的吗?

不推荐使用的Environment.getExternalStorageDirectory().getAbsolutePath()返回的值不同于新的getExternalFilesDir(空)?

为什么使用JDK21获取锁定锁比使用JDK11慢

多重延迟签名

在Java 17中使用两个十进制数字分析时间时出错,但在Java 8中成功

Jolt变换JSON数组问题

如何从日期中截取时间并将其传递给组件?

在Ubuntu 23.10上使用mp3创建JavaFX MediaPlayer时出错

Java创建带有扩展通配符的抽象处理器

我如何为我的Java抵押贷款代码执行加薪操作(&Q)

将stringBuilder + forloop转换为stream + map

STREAMS减少部分结果的问题

处理4.3问题:javax.xml.ind包不存在(&Q;).您可能在学习GitHub教程时遗漏了库.&Q

当我将JTextField的getText函数与相等的String进行比较时;t返回true

org.springframework.web.HttpRequestMethodNotSupportedException:请求方法';帖子';不支持

Java泛型方法重载

无泄漏函数的Java DRY

如何转换Vector<;对象>;转换为int?