Информация об изменениях

Сообщение Re[2]: Помогите с многопоточным кодом от 05.09.2022 19:33

Изменено 05.09.2022 19:37 vsb

Re[2]: Помогите с многопоточным кодом
Здравствуйте, StanislavK, Вы писали:

SK>Не понятно как это может работать как можно быстрее и ваще хоть как-то работать. Учитывая условие задачи это функция все равно не будет возвращать значения быстрее чем раз в миллисекунду, так как условие y > prevY будет истинно раз 20-30, если повезет. Так что ставьте synchronized.


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

Если интересно — полный код, но там специфика UUID формата. Генерацию случайного числа я заменил на счетчик.

public class AscUuidGen {
    private static final SecureRandom secureRandom = new SecureRandom();
    private static AtomicLong timeMillis;
    private static AtomicInteger counter;

    public static UUID next() {
        long timeMillis2;
        int counter2;

        while (true) {
            long timeMillis1 = timeMillis.get();
            timeMillis2 = currentTimeMillis();
            if (timeMillis2 < timeMillis1) {
                continue;
            }

            int counter1 = counter.get();
            counter2 = timeMillis1 == timeMillis2 ? counter1 + 1 : 0;
            if (counter2 >= 0x10_00) {
                continue;
            }

            if (!timeMillis.compareAndSet(timeMillis1, timeMillis2)) {
                continue;
            }
            if (!counter.compareAndSet(counter1, counter2)) {
                continue;
            }

            break;
        }

        long lsb1 = secureRandom.nextLong(0x40_00_00_00_00_00_00_00L);

        long msb = timeMillis2 << 16 | 0x40_00 | counter2;
        long lsb = 0x80_00_00_00_00_00_00_00L | lsb1;
        return new UUID(msb, lsb);
    }
}


import java.security.SecureRandom;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;

import static java.lang.Runtime.getRuntime;
import static java.lang.System.currentTimeMillis;

public class AscUuidGen {
    private static final ThreadLocal<SecureRandom> secureRandom = ThreadLocal.withInitial(SecureRandom::new);
    private static long timeMillis;
    private static int counter;

    public static synchronized UUID next() {
        long currentTimeMillis;
        int currentCounter;

        do {
            currentTimeMillis = currentTimeMillis();
            assert currentTimeMillis >= timeMillis;
            currentCounter = timeMillis == currentTimeMillis ? counter + 1 : 0;
        } while (currentCounter >= 0x10_00);

        timeMillis = currentTimeMillis;
        counter = currentCounter;

        long lsb1 = secureRandom.get().nextLong(0x40_00_00_00_00_00_00_00L);

        long msb = currentTimeMillis << 16 | 0x40_00 | currentCounter;
        long lsb = 0x80_00_00_00_00_00_00_00L | lsb1;
        return new UUID(msb, lsb);
    }

    // test code

    private static final AtomicLong speed = new AtomicLong();

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < getRuntime().availableProcessors(); i++) {
            new Thread(AscUuidGen::main1).start();
        }
        long speed1 = 0;
        while (true) {
            Thread.sleep(1000);
            long speed2 = speed.get();
            System.out.println(speed2 - speed1);
            speed1 = speed2;
        }
    }

    public static void main1() {
        UUID uuid1 = next();
        while (true) {
            UUID uuid2 = next();
            if (uuid1.compareTo(uuid2) >= 0) {
                System.out.println("error");
            }
            speed.incrementAndGet();
        }
    }
}
Re[2]: Помогите с многопоточным кодом
Здравствуйте, StanislavK, Вы писали:

SK>Не понятно как это может работать как можно быстрее и ваще хоть как-то работать. Учитывая условие задачи это функция все равно не будет возвращать значения быстрее чем раз в миллисекунду, так как условие y > prevY будет истинно раз 20-30, если повезет. Так что ставьте synchronized.


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

Если интересно — полный код, но там специфика UUID формата. Генерацию случайного числа я заменил на счетчик.

public class AscUuidGen {
    private static final SecureRandom secureRandom = new SecureRandom();
    private static AtomicLong timeMillis;
    private static AtomicInteger counter;

    public static UUID next() {
        long timeMillis2;
        int counter2;

        while (true) {
            long timeMillis1 = timeMillis.get();
            timeMillis2 = currentTimeMillis();
            if (timeMillis2 < timeMillis1) {
                continue;
            }

            int counter1 = counter.get();
            counter2 = timeMillis1 == timeMillis2 ? counter1 + 1 : 0;
            if (counter2 >= 0x10_00) {
                continue;
            }

            if (!timeMillis.compareAndSet(timeMillis1, timeMillis2)) {
                continue;
            }
            if (!counter.compareAndSet(counter1, counter2)) {
                continue;
            }

            break;
        }

        long lsb1 = secureRandom.nextLong(0x40_00_00_00_00_00_00_00L);

        long msb = timeMillis2 << 16 | 0x40_00 | counter2;
        long lsb = 0x80_00_00_00_00_00_00_00L | lsb1;
        return new UUID(msb, lsb);
    }
}


import java.security.SecureRandom;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;

import static java.lang.Runtime.getRuntime;
import static java.lang.System.currentTimeMillis;

public class AscUuidGen {
    private static final ThreadLocal<SecureRandom> secureRandom = ThreadLocal.withInitial(SecureRandom::new);
    private static long timeMillis;
    private static int counter;

    public static synchronized UUID next() {
        long currentTimeMillis;
        int currentCounter;

        do {
            currentTimeMillis = currentTimeMillis();
            assert currentTimeMillis >= timeMillis;
            currentCounter = timeMillis == currentTimeMillis ? counter + 1 : 0;
        } while (currentCounter >= 0x10_00);

        timeMillis = currentTimeMillis;
        counter = currentCounter;

        long lsb1 = secureRandom.get().nextLong(0x40_00_00_00_00_00_00_00L);

        long msb = currentTimeMillis << 16 | 0x40_00 | currentCounter;
        long lsb = 0x80_00_00_00_00_00_00_00L | lsb1;
        return new UUID(msb, lsb);
    }

    // test code

    private static final AtomicLong speed = new AtomicLong();

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < getRuntime().availableProcessors(); i++) {
            new Thread(AscUuidGen::main1).start();
        }
        long speed1 = 0;
        while (true) {
            Thread.sleep(1000);
            long speed2 = speed.get();
            System.out.println(speed2 - speed1);
            speed1 = speed2;
        }
    }

    public static void main1() {
        UUID uuid1 = next();
        while (true) {
            UUID uuid2 = next();
            if (uuid1.compareTo(uuid2) >= 0) {
                System.out.println("error");
            }
            speed.incrementAndGet();
        }
    }
}


Первый вариант выдаёт 2 млн значений в секунду, второй вариант выдаёт около 3, формат ограничивает 4 млн в секунду.