Изменчивая переменная для операций чтения-записи в Java

На объекте вы можете достичь этого с помощью setattr

>>> class A(object): pass
>>> a=A()
>>> setattr(a, "hello1", 5)
>>> a.hello1
5
0
задан gaby 18 March 2019 в 18:23
поделиться

1 ответ

Оператор stop = true; не является операцией «чтение-запись», а только записью . Он вообще не читает старое значение переменной. Если предыдущее значение stop было true, утверждение не имело никакого эффекта, не заметив разницу.

Операция «чтение-изменение-запись», также известная как операция «чтение-обновление-запись», подразумевает операцию, которая считывает предыдущее значение, вычисляет новое значение на его основе и записывает новое значение обратно в переменную. , Проблема с этой операцией, когда не используется специальная атомарная конструкция обновления, состоит в том, что к тому времени, когда выполняется запись, может произойти одновременное обновление, поэтому переменная перезаписывается вычисленным значением, которое основано на устаревшем предыдущем значении .

Для вашей переменной boolean операции «чтение-изменение-запись» могут выглядеть как

if(!stop) stop = true;

или

stop = !stop;

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

Операция «чтение-запись», то есть без промежуточного «изменения / обновления», была бы операцией, которая считывает старое значение для последующего использования и записывает новое значение, не основанное на старом значении. Как

Type old = variable;
variable = newValue;
// use old here

, которые все еще будут подвержены потерянным обновлениям, если не будут сделаны атомарно. Таким образом, такая операция также требует больше, чем переменная volative. Например. AtomicInteger.getAndSet или VarHandle.getAndSet .

Итак, расширив свой пример до

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

public class StopThread {
    private static volatile boolean stop;

    public static void main(String[] args) throws InterruptedException { 

        new Thread(new Runnable() {
            @Override
            public void run() {
                while(!stop) {
                    System.out.println("In while...");
                }
            }
        }).start();
        for(int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1)); 
                    boolean old = stop; // broken because
                    stop = true;        // not atomic
                    System.out.println(old? "other thread was faster": "sent stop signal");
                }
            }).start();
        }
    }
}

, несколько потоков могут подумать, что они отправили сигнал остановки.

Если вы исправите код на

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.LockSupport;

public class StopThread {
    private static final AtomicBoolean stop = new AtomicBoolean();

    public static void main(String[] args) throws InterruptedException { 

        new Thread(new Runnable() {
            @Override
            public void run() {
                while(!stop.get()) {
                    System.out.println("In while...");
                }
            }
        }).start();
        for(int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1)); 
                    boolean old = stop.getAndSet(true);
                    System.out.println(old? "other thread was faster": "sent stop signal");
                }
            }).start();
        }
    }
}

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

0
ответ дан Holger 18 March 2019 в 18:23
поделиться