首页 > 解决方案 > 在另一个 Runnable 实现类中传递 Runnable 实例,其中前者的 run() 方法需要后者的引用

问题描述

我有一个类“ResourceConsumerThread”,它扩展了 Thread 并定义了一些行为。此类的多个实例(即多个线程)将具有不同的行为。我试图在创建 ResourceConsumerThread 类的实例时通过功能接口(Runnable)传递这些行为。ResourceConsumerThread 的 run() 方法只是调用 lambda 的方法 - run()。但是,我的要求是我传递的 lambda 需要引用它传递到的 ResourceConsumerThread 对象。

 public class ResourceConsumingThread extends Thread {
        //threads which have acquired resources that this thread is asking for.
        private List<ResourceConsumingThread> dependencyList;
        private List<Resource> acquiredResources;
        private List<Resource> requestedResources;
        private volatile boolean isDeadlockDetected;
        private final String id;
        private static int threadIdGenerator;
        private final Runnable runnableBody;

        private ResourceConsumingThread( Runnable runnableBody) {
            this.dependencyList = new ArrayList<>();
            this.acquiredResources = new ArrayList<>();
            this.requestedResources = new ArrayList<>();
            this.id = "T" + threadIdGenerator++;
            this.runnableBody = runnableBody;
        }

 @Override
    public void run() {
        System.out.println("Running body for thread : " + id);
        if(runnableBody != null){
           runnableBody.run();
        }else{
            System.out.println("ERROR...threadBody can't be null.");
        }
    }
    }

此类的用户将使用它,如下所示:

public void callerMethod(){
ResourceConsumingThread t1 = lockManager.createNewThread(new Runnable() {
            @Override
            public void run() {
                lockManager.acquireLockOnResourceForThread(new Resource(), t1);
            }
        });
}

但是,由于 t1 尚未构建,我无法在 run() 方法中使用它 - 我收到编译器错误。

知道如何实现这一点,即使它涉及一些设计返工?主要要求是:

  1. LockManager.acquireLockOnResourceForThread() 需要知道哪个 ResourceConsumingThread 实例正在请求哪个 Resource。
  2. ResourceConsumingThread 的 run() 方法应该能够在不同的线程中执行不同的逻辑。

更新了我正在尝试的答案(不确定它是否正确的做法)。仍在等待通过社区获得潜在解决方案的更多天使。

final Map<String, Resource> resourceMap = new HashMap<>();
        resourceMap.put("R1", new Resource());

        final ResourceConsumingThread t1 = new ResourceConsumingThread();
        Runnable t1Runnable = new Runnable() {
            @Override
            public void run() {
                lockManager.acquireLockOnResourceForThread(resourceMap.get("R1"), t1);
            }
        };
        t1.setRunnableBody(t1Runnable);
        t1.start();
        t1.join();

更新(在@Cliff 的评论之后):

 ResourceConsumingThread t = lockManager.createNewThread(() -> {

           lockManager.acquireLockOnResourceForThread(new Resource(), (ResourceConsumingThread) Thread.currentThread());
       });

标签: javamultithreadinglambda

解决方案


我建议创建一个在其 run 方法中接受 ResourceConsumingThread 的功能接口。

interface ResourceRunnable {
    void run(ResourceConsumingThread resourceThread);
}

这意味着将 ResourceConsumingThread 的构造函数更改为接受 ResourceRunnable。然后你可以这样做:

public void callerMethod(){
ResourceConsumingThread t1 = lockManager.createNewThread(new Runnable() {
            @Override
            public void run(ResourceConsumingThread resourceThread) {
                lockManager.acquireLockOnResourceForThread(new Resource(), resourceThread);
            }
        });
}

ResourceConsumingThread 将在内部调用 ResourceRunnable.run(this) 。

更新: 正如我通过评论建议的那样,另一种方法是:

ResourceConsumingThread t = lockManager.createNewThread(() -> {

           lockManager.acquireLockOnResourceForThread(new Resource(), (ResourceConsumingThread) Thread.currentThread());
       });

推荐阅读