может быть, то, что я надеюсь выразить, не так ясно, первый случай - пример того, когда и как использовать
volatile
, И чтобы программа работала успешно, Нам нужно добавить volatile.
во-вторых, в надежде показать, что даже без volatile программа будет работать успешно. И я надеюсь узнать, почему это произойдет без «летучих»
В первом примере типичный образец использования летучих
public static int num=1;
public static class MyThread extends Thread {
// flag
private boolean flag = false ;
public boolean isFlag() { return flag;}
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) { e.printStackTrace();
}
// change flag to true
this.flag = true ;
System.out.println("flag = " + flag);
this.flag=true;
}
}
// main
static void testWithOutVolatile(){
MyThread t=new MyThread();
t.start();
while(true) {
boolean is=t.flag;
if (is) {
System.out.println("run===== = ");
}
}
}
После запуска основной поток не найдет изменение флага, если только не используется volatile
Однако в примере поток 2 неожиданно получил смену флага, почему это произошло?
static int amb=0;
static void testSimple(){
Thread t1=new Thread(()->{
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
amb++;
});
Thread t2=new Thread(()->{while(true) {
if (amb == 0) {
System.out.println("no");
}
if (amb != 0) {
System.out.println("SUc");
break;
}
}});
t2.start();
t1.start();
}
И после попытки я нахожу, если я удалю код
if (amb == 0) {
System.out.println("no");
}
он будет работать, как я и думал, thread2 не может получить изменение.
Спасибо за ответ, QwQ
извините, может быть, то, что я надеюсь выразить, не так ясно, первый случай - это пример того, когда и как использовать volatile
, и чтобы программа работала успешно, нам нужно добавить volatile. во-вторых, в надежде показать, что даже без volatile программа будет работать успешно. И я надеюсь узнать, почему это произойдет без «летучих»
На самом деле, @SusanMustafa - это не совсем так, что так и должно быть volatile
. Есть и другие способы. Например, используя synchronized
соответствующим образом, или используя тип AtomicXxx
, или используя поле final
.
@StephenC Да, Стивен, возможно, мой комментарий может создать впечатление, что это единственный способ, однако я привел пример переполнения стека для большего пояснения.
@StephenC ххх, спасибо, понял причины, чувствует себя хорошо :P
Может быть, во втором случае оператор io обновляет буферную зону Thread
Thread t2=new Thread(()->{while(true) {
System.out.println("no");
if (amb != 0) {
System.out.println("SUc");
break;
}
}});
если я использую оператор io (Sout), он будет работать успешно.
Таким образом, я продолжаю находить причины в println. И я нахожу истинную причину
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
синхронизировано вызвало переключение потока
а с выключателем буферная зона нити была свободна,
поэтому thread2 читает новое значение
Честно говоря, я не понимаю вашего вопроса, но позвольте мне прояснить несколько вещей. Чтобы переменная могла делиться своим состоянием между несколькими потоками в Java (в режиме реального времени), она должна быть изменчивой. Использование статических переменных: они совместно используются потоками, но изменения, сделанные в одном потоке, могут быть не сразу видны другому потоку, что создает впечатление наличия двух копий переменной. stackoverflow.com/questions/13582395/… xspdf.com/resolution/52087767.html