#java #volatile
#java #volatile
Вопрос:
Я изучаю знания параллелизма в Java. Что касается ключевого слова volatile, оно должно сделать переменную видимой в разных потоках. Но в моем демонстрационном коде, похоже, оно работает не так, как ожидалось. Метод run()
в классе, который реализует Runnable
, никогда не остановится.
public class VisibilityDemo {
public static void main(String[] args) throws InterruptedException {
TimeConsumingTask timeConsumingTask = new TimeConsumingTask();
Thread thread = new Thread(new TimeConsumingTask());
thread.start();
Thread.sleep(3000);
timeConsumingTask.cancel();
}
}
class TimeConsumingTask implements Runnable {
private volatile boolean toCancel = false;
@Override
public void run() {
while (! toCancel) {
System.out.println("executing...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (toCancel) {
System.out.println("Task was canceled.");
} else {
System.out.println("Task done.");
}
}
public void cancel() {
toCancel = true;
System.out.println(this " canceled.");
}
}
Комментарии:
1.
timeConsumingTask
никогда не запускается.2. «Что касается ключевого слова volatile, оно должно делать переменную видимой в разных потоках».: Нет, volatile означает, что эта переменная считывается не из кэша, а из основной памяти.
3. @gkhaos — Это сложнее, чем это.
4. @StephenC действительно, переменные, характеризуемые изменчивостью, не являются целью оптимизации компилятора (что-нибудь еще?). Я хотел сказать, что «volatile» ничего не говорит о доступности (например, частной или общедоступной).
Ответ №1:
В вашем основном методе у вас есть два экземпляра вашей задачи:
public static void main(String[] args) throws InterruptedException {
TimeConsumingTask timeConsumingTask = new TimeConsumingTask(); //<-- one
Thread thread = new Thread(new TimeConsumingTask()); //<-- two
thread.start();
Thread.sleep(3000);
timeConsumingTask.cancel(); //<-- cancel() on first
}
}
Вы передаете одно Thread
из них конструктору, а затем вызываете cancel
другое. Вам нужно вызвать cancel
экземпляр, переданный Thread
, например, так:
public static void main(String[] args) throws InterruptedException {
TimeConsumingTask timeConsumingTask = new TimeConsumingTask();
Thread thread = new Thread(timeConsumingTask); //<-- difference here
thread.start();
Thread.sleep(3000);
timeConsumingTask.cancel();
}
}