Передача экземпляра Runnable в другой реализующий класс Runnable, где для предыдущего метода run () требуется ссылка на более поздний - PullRequest
0 голосов
/ 04 мая 2018

У меня есть класс ResourceConsumerThread, который расширяет Thread и определяет некоторое поведение. Несколько экземпляров этого класса (то есть несколько потоков) будут иметь разное поведение. Я пытаюсь передать эти поведения через функциональный интерфейс (Runnable) при создании экземпляра класса ResourceConsumerThread. Метод run () ResourceConsumerThread просто вызывает метод лямбды - run (). Однако мое требование заключается в том, что передаваемая лямбда-ссылка должна ссылаться на объект 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 запрашивает какой ресурс.
  2. Метод run () ResourceConsumingThread должен иметь возможность выполнять разные логики в отдельных потоках.

ОБНОВЛЕНО ответом, который я пытаюсь (не уверен, что это правильно). Все еще жду дополнительных ангелов о возможном решении через сообщество.

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();

ОБНОВЛЕНО (после комментариев @ Клиффа):

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

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

Ответы [ 2 ]

0 голосов
/ 04 мая 2018

Я бы предложил создать функциональный интерфейс, который принимает ResourceConsumingThread в своем методе run.

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());
       });
0 голосов
/ 04 мая 2018

Вы можете просто использовать this в анонимном внутреннем классе:

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

Это передаст ссылку на Runnable, который известен в callerMethod как t1.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...