Перекрестные вызовы функций с Java - PullRequest
3 голосов
/ 20 декабря 2011

Я хотел бы знать, как вызывать различные функции в Java.Прямо сейчас я делаю так, чтобы написать мою функцию run () моего потока следующим образом:

public volatile boolean invokeMyFunction = false;

public void run() {
    while(true) { 
        if(invokeMyFunction) {
            MyFunction();
            invokeMyFunction = false;
        }
    }
}

, и если я хочу запустить функцию MyFunction () извне этого потока, напишите "whateverobject".invokeMyFunction = true ", и он запустит мою функцию из потока, потому что этот цикл его подхватит.Это прекрасно работает для меня, но он использует 100% моего процессора из-за цикла while (true).Я мог бы исправить это, просто ударив Thread.sleep (1000) внутри цикла, но это кажется грязным, и я не могу не поверить, что есть лучший способ сделать это.

Ответы [ 4 ]

4 голосов
/ 20 декабря 2011

Я думаю, здесь самый простой и дружественный к процессору способ добиться этого -

public void run() {
    while(true) { 
        synchronized(foo) {
            while(!invokeMyFunction) {
                foo.wait();
            }
        }
        MyFunction();
        invokeMyFunction = false;
    }
}

Приведенный выше код работает в своем собственном потоке. Другой поток может сделать это, чтобы первый поток запустил MyFunction ():

invokeMyFunction = true;
foo.notifyAll();

Обратите внимание, что a) Вы не можете сделать invokeMyFunction логическим значением и синхронизировать его, потому что во всем Java есть только два логических значения :) б) Если invokeMyFunction установлена ​​n раз, она все равно может выполняться меньше раз, если invokeMyFunction установлена ​​в значение true, но не ложно. c) Использование BlockingQueue может быть проще и позволит потоку 1 запускать произвольные функции:

while(true) {
    Runnable next = queue.take();
    next.run()
}

И другой поток скажет ему запустить MyFunction так:

queue.put(new Runnable() {
    void run() {
        MyFunction();
    }
});

Мне кажется это проще :) Кроме того, если вы хотите, чтобы n потоков запускало все, что поступает через очередь, вам просто нужно создать n потоков, которые прослушивают очередь. Или вы можете узнать, как использовать пулы потоков: http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html

Примечание:

queue.put () блокируется до тех пор, пока в BlockingQueue не будет доступно новое пространство, т.е. оно блокируется, если заполнено. Просмотрите документы по реализации используемой вами реализации BlockingQueue, чтобы узнать, имеет ли ваша очередь ограничение. В любом случае, убедитесь, что вы не добавляете больше элементов для работы, чем можете обрабатывать слишком долго.

2 голосов
/ 20 декабря 2011

В вашем коде есть несколько дыр, кроме того факта, что вы собираетесь загружать процессор.

Что если ваши другие потоки хотят, чтобы этот поток вызывался дважды, за время, которое требуется MyFunction длявыполнить?В конечном итоге вы пропустите один вызов.

Улучшение может быть следующим:

public volatile boolean invokeMyFunction = false;

public void run() {
    while(true) { 
        if(invokeMyFunction) {
            // Moved here.
            invokeMyFunction = false;
            MyFunction();
        }
    }
}

Однако это только делает состояние гонки менее вероятным, а не невозможным.

Вы можетелучше использовать BlockingQueue, как я предложил здесь .Заставьте другую ветку опубликовать что-то в очереди, которую читает эта ветка.Вы также не станете так загружать процессор.

2 голосов
/ 20 декабря 2011

Вы можете поместить монитор в свою ветку и ждать на этом мониторе. Когда вы вызываете функцию, скажите монитору, чтобы он освободил кого-то (и он должен иметь только этого), который может запустить вашу функцию, а затем снова вернуться к ожиданию.

С другой стороны, нет ничего плохого в маршруте сна. Я понимаю, почему вы бы назвали это грязным, но у вас меньше шансов сделать глупую ошибку и обеспечить более слабую связь между вашими сервисами.

(Примечание: вам не нужно помещать монитор в поток. Вы можете использовать этот объект в качестве монитора вместо внутреннего монитора. Но затем вы открываете себя кому-то, кто потенциально может ему помешать, так что это Лучше всего использовать частный внутренний объект в качестве монитора.)

1 голос
/ 20 декабря 2011

Ваша схема мне странна. Зачем запускать поток, но подождать до неизвестного времени в будущем, чтобы получить команду на запуск? Почему бы просто не запустить его позже?

РЕДАКТИРОВАТЬ ДОБАВЛЕНО, чтобы уточнить до кодера свечения

EDIT REMOVED - Мой плохой, я неправильно понял его вопрос, он хочет иметь возможность вызывать MyFunction несколько раз. В этом случае он должен использовать какую-то очередь, как предложено в других ответах

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