Это 29-й день моего участия в Gengwen Challenge.Подробности о мероприятии:Обновить вызов.
Сразу после предыдущегоПривет, можешь рассказать о ключевом слове volatile? (Четыре)
4.6 happens-before
В принципе должно бытьJMMглава говорит,happens-beforeПринципJMMосновные понятия. Но поскольку все дело в наглядности и порядке, давайте сначала кратко упомянем об этом.
Принцип «происходит до» гласит, что предыдущая операция должна быть видна последующей операции. Другими словами, соблюдение этого правила в многопоточной среде может обеспечить видимость общих переменных для нескольких операций.
4.6.1 happens-before && as-if-serial
happens-beforeвзаимоотношения в природе иas-if-serialСемантика — это одно и то же.
-
happens-beforeа такжеas-if-serialУбедитесь, что результаты многопоточного и однопоточного выполнения не изменились соответственно. -
as-if-serialВидимость, которую семантика создает для пользователя, состоит в том, что в последовательности программы выполняется один поток;happens-beforeВнешний вид, вызванный семантикой, положительный Правильно синхронизированная многопоточная программаhappens-beforeвыполняются в указанном порядке.
Цель этих двух правил — максимально улучшить параллелизм выполнения программы без изменения результата выполнения программы.
4.6.2 happeds-beforeправило
**"JSR-133: Модель памяти Java и спецификация потоков"** определяет следующие правила "происходит до".
Правила порядка выполнения программы: каждая операция в потоке выполняется до любых последующих операций в этом потоке.
правила порядка программыПроще говоря, чтобы обеспечить параллелизм, вы можете оптимизировать и настроить порядок выполнения так, как вам хочется, но результат всегда один и тот же. Это общая программа.
Следите за правилами блокировки: отпирание замка происходит до последующего запирания замка.
Правила блокировки монитора
static int y = 1;
static void testMonitorRule(){
synchronized(Object.class){
if(y==1){
y=2;
}
}
}
Поток 1 получает блокировку первым и изменяет значение y на 2. После того, как поток 2 получает блокировку, он может непосредственно видеть, что y==2.
Правила для изменчивых переменных: запись в изменчивое поле происходит до любой последующей записи в изменчивое поле. читать.
правила изменяемой переменной
static int i = 1;
static volatile boolean flag = false;
static void testVolatileRuleReader(){
i=2;//1
flag=true;//2
}
static void testVolatileRuleWriter(){
if(flag){//3
assert i == 2;//4
}
}
Итак, шаг 3 — это чтение, и вы можете увидеть запись шага 2.
Переходный: если А происходит раньше В, а В происходит раньше С, то А происходит раньше С.
транзитивное правило, чуть вышеvolatileВ примере правила говорится, что шаг 1 должен произойти до шага 4.
правило start(): если поток A выполняет операцию ThreadB.start() (запускает поток B), то Операция ThreadB.start() происходит перед любой операцией в потоке B.
правила запуска()
static void testStartRule(){
AtomicInteger x = new AtomicInteger(1);
final Thread t = new Thread(() -> {
assert x.get() == 2;
});
x.set(2);
t.start();
}
Основной поток вызывает дочерний потокt.start()Все предыдущие операции с общими переменными видны дочерним потокам.
Правило join(): если поток A выполняет операцию ThreadB.join() и успешно возвращается, то любая операция в потоке B происходит до того, как поток A успешно вернется из операции ThreadB.join().
правила присоединения()
static void testJoinRule() throws InterruptedException {
AtomicInteger x = new AtomicInteger(1);
final Thread t = new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
x.set(2);
});
t.start();
t.join();
assert x.get() == 2;
}
вызвать дочерний поток в основном потокеt.join(), все изменения общих переменных дочерними потоками видны основному потоку.
5 Резюме
5.1 volatileсценарии использования
volatileсуществуетJavaОн часто используется в параллелизме, напримерAtomicв упаковкеvalue,так же какAbstractQueuedLongSynchronizerсерединаstateпеременныеvolatileУкрашено, чтобы гарантировать видимость памяти.
В нашем процессе разработки также есть некоторые приложения, такие как.
Используйте один поток, чтобы остановить другой поток, изменив бит флага
public static volatile boolean run = true;
public static void main(String[] args) throws InterruptedException {
final Thread t = new Thread(() -> {
int i = 0;
while (!run) {
i++;
Thread.yield();
}
});
t.start();
TimeUnit.SECONDS.sleep(10);
run= true;
}
Блокировки с двойной проверкой реализуют шаблон singleton.
public class DoubleCheckingLock {
private static volatile Instance instance;
public static Instance getInstance(){
if(instance == null){
synchronized (DoubleCheckingLock.class){
if(instance == null){
instance = new Instance();
}
}
}
return instance;
};
static class Instance { }
}
В частности, как этого добиться, см. ** "Искусство параллельного программирования на Java"** в этой хорошей книге.
5.2 Закрытие
Эта статья начинается с примера и приводит к проблемам видимости и порядка работы с общими переменными в многопоточной среде. В сочетании с аппаратной средой анализируется, что для эффективного использования ресурсов компьютера и улучшения параллелизмаCPUКэширование было введено, чтобы вызвать проблемы. Чтобы решить проблему согласованности, вызванную кешем, была проанализирована еще одна волна.MESIСоглашение было окончательно проанализировано.volatileОсновной принцип内存屏障.
На вопросы, упомянутые в начале статьи, можно будет ответить уже после прочтения этой статьи. оsynchronizedВопрос в этой частиsynchronizedАнализ воссоединения глав.
Брат, не паникуй! Не стесняйтесь оставлять лайки, обсуждать и комментировать. Добро пожаловать в колонку интервьюНе паникуйте, когда сталкиваетесь | Параллельное программирование на Java, Не беспокойтесь о повышении зарплаты во время собеседования. Также добро пожаловать, чтобы следовать за мной, я должен быть лучшим человеком.