Как выполняется переключение потоков?

Как я понимаю, в контексте процесса переключение резервных копий ОС "регистры" и указатель инструкции (также часть регистра).

Но в случае переключения между потоками внутри процесса ОС будет делать резервную копию полной памяти регистров и стека?

Причина, по которой я спрашиваю, заключается в том, чтобы понять, имеет ли ключевое слово volatile Java какое-либо значение в случае одноядерных процессоров.

Ответ 1

если ключевое слово volatile Java имеет какое-либо значение в случае одноядерных процессоров.

Оптимизация, используемая jit-компилятором, может вызвать неожиданное поведение.

static boolean foo = true;

public void bar(){
   while(foo){
     //doSomething
     //do not modify foo in here
   }
}

это может быть оптимизировано, так как foo не изменяется в цикле.

public void bar(){
    while(true){
     //Now this loop never ends
     //changes to foo are ignored
    }
}

make foo volatile сообщит компилятору jit, что foo может быть изменен другим потоком, и доступ к нему не должен быть оптимизирован.

Это допустимое поведение, поскольку доступ к сквозным потокам гарантирован только с

  • летучие и синхронизированные ключевые слова
  • классы, которые должны быть потокобезопасными (например, java.util.concurrent. *)

Обновление

Ключевое слово volatile не влияет на переключение контекста, однако оно влияет на оптимизацию чтения и записи переменных. Это не только влияет на использование кеша процессора (важно для многоядерных систем), но и оптимизаций, используемых компилятором только во времени, как показано выше (важно для всех систем).

Ответ 2

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

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

Ответ 3

понять, что ключевое слово volatile Java имеет какое-либо значение в случае одноядерных процессоров.

Эта линия мышления неразумна. Вы должны программировать в соответствии с (документированным) определением API и виртуальной машины. Вы не должны полагаться на что-то (в данном случае на эффект volatile), имеющее особый эффект или недостаток эффекта, который не является частью его документированного определения. Даже если эксперимент предполагает, что он имеет особое поведение в определенных обстоятельствах. Потому что он будет укусить вас.

Ответ 4

Проверьте JSR 133 и, в частности, раздел "Что делает volatile?"

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

Это полезное введение и описание того, как volatile работает с моделью памяти JVM.

Ответ 5

Да, даже для одноядерных процессоров, volatile по-прежнему полезен. Он сообщает компилятору, что значение нужно перечитывать из памяти каждый раз, когда он читает (поскольку другой поток может его обновлять), а не просто кэшироваться в регистре.

Ответ 6

Я знаю, что делает volatile, но я пытаюсь понять, почему это необходимо. Позвольте мне уточнить.

Как упоминалось выше josefx. Если у нас есть что-то вроде: -

while(run) {
 //do something but don't modify run
}

Если какой-то другой поток превратит run в false, тогда цикл while никогда не закончится. Как уже упоминалось ранее Yuval A, во время переключения контекста потока также сохраняются регистры. Поэтому я думаю, что это работает так.

Если какой-либо поток изменяет значение run, значение будет изменено только в регистре. Во время переключения контекста потока Java не будет синхронизировать это значение регистра с копией в ОЗУ, если явно не указано как volatile. Таким образом, каждый поток будет работать со своей версией run. Но это понятие не относится к непримитивам и примитивам, таким как integer и т.д., Которые не будут вписываться полностью в регистр, заставляя их синхронизироваться с копией RAM.