Неизменный 100%, но все еще не потокобезопасный - PullRequest
0 голосов
/ 17 октября 2018

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

public final class ImmutableGaugeV4 {
private final long max, current;

public ImmutableGaugeV4(final long max) {
    this(max, 0);
}

private ImmutableGaugeV4(final long max, final long current) {
    this.max = max;
    this.current = current;
}

public final ImmutableGaugeV4 increase(final long increament) {
    final long c = current;
    return new ImmutableGaugeV4(max, c + increament);
}

public final long getCurrent() {
    return current;
}

public final long getPerc() {
    return current * 100 / max;
}

@Override
public final String toString() {
    return "ImmutableGaugeV4 [max=" + max + ", current=" + current + "](" + getPerc() + "%)";
}
 }

ааааа

public class T4 {
public static void main(String[] args) {
    new T4().x();
}

ImmutableGaugeV4 g3 = new ImmutableGaugeV4(10000);

private void x() {
    for (int i = 0; i < 10; i++) {
        new Thread() {
            public void run() {
                for (int j = 0; j < 1000; j++) {
                    g3 = g3.increase(1);
                    System.out.println(g3);
                }
            }

        }.start();
    }
}
}

Иногда я получаю правильные результаты, и в большинстве случаев я не

ImmutableGaugeV4 [max=10000, current=9994](99%)
ImmutableGaugeV4 [max=10000, current=9995](99%)
ImmutableGaugeV4 [max=10000, current=9996](99%)
ImmutableGaugeV4 [max=10000, current=9997](99%)

Что не так с этим неизменным объектом?Чего не хватает, чтобы сделать его поточно-ориентированным без использования встроенных блокировок?

Ответы [ 2 ]

0 голосов
/ 17 октября 2018

Ни

final long c = current;
return new ImmutableGaugeV4(max, c + increament);

, ни

g3 = g3.increase(1);

не являются поточно-ориентированными.Эти сложные действия не являются атомарными.

Рекомендую прочитать Брайан Гетц "Параллелизм Java на практике": главы, посвященные сложным действиям и проблемам "публикации и побега".

0 голосов
/ 17 октября 2018

Ваша проблема в том, что вы не используете потокобезопасные операции для числовых переменных max и current.Из-за этого многие потоки могут получить от них одно и то же значение, даже если оно уже было изменено.

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

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

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicLong.html

Всякий раз, когда вы используете многопоточность, вы должны использовать объекты, защищенные от потоков, такие как семейство Atomic,ConcurrentHashMap для карт и т. Д.

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...