How to use long instead of int can have a bulletproof next method - Effective Java

Consider the following code selected from Joshua Bloch - Effective Java, page 263

// Broken - requires synchronization!
private static volatile int nextSerialNumber = 0;
public static int generateSerialNumber() {
    return nextSerialNumber++;
}

One way to fix the generateSerialNumber method is to add a synchronized modifier to its declaration. This ensures that multiple calls will not alternate and that each call will see the effects of all previous calls. Once you do this, you can and should remove the mutable modifier nextSerialNumber. To a bulletproof method, use a long one instead of an int, or throw an exception if nextSerialNumber is going to wrap it.

  • I understand that we can delete volatileafter we create generateSerialNumber synchronized, since it is redundant. But does he do any harm? Any performance limitation if I have both synchronized and unstable, e.g.

private static volatile int nextSerialNumber = 0;
public static synchronized int generateSerialNumber() {
    return nextSerialNumber++;
}

  • What does it mean to use long instead of int? I do not understand how this bulletproof method?
+3
source share
4 answers

It just means that long will contain a lot more numbers than int.

or throw an exception if nextSerialNumber is going to wrap

, , , . , . , , . , .

long . , .

+8

, long int ?

, , . int, ( , nextSerialNumber int), () int, , , : -)

+2

IMHO volatile/AtomicInteger . - . , , volatile .

Java 6 update 23.

Average time to synchronized++ 10000000 times. was 110368 us
Average time to synchronized on the class ++ 10000000 times. was 37140 us
Average time to volatile++ 10000000 times. was 19660 us

, .

:

static final Object o = new Object();
static int num = 0;

static final AtomicInteger num2 = new AtomicInteger();

public static void main(String... args) throws InterruptedException {
    final int runs = 10 * 1000 * 1000;
    perfTest(new Runnable() {
        public void run() {
            for (int i = 0; i < runs; i++)
                synchronized (o) {
                    num++;
                }
        }

        public String toString() {
            return "synchronized++ " + runs + " times.";
        }
    }, 4);
    perfTest(new Runnable() {
        public void run() {
            for (int i = 0; i < runs; i++)
                synchronized (Main.class) {
                    num++;
                }
        }

        public String toString() {
            return "synchronized on the class ++ " + runs + " times.";
        }
    }, 4);
    perfTest(new Runnable() {
        public void run() {
            for (int i = 0; i < runs; i++)
                num2.incrementAndGet();
        }

        public String toString() {
            return "volatile++ " + runs + " times.";
        }
    }, 4);
}

public static void perfTest(Runnable r, int times) throws InterruptedException {
    ExecutorService es = Executors.newFixedThreadPool(times);
    long start = System.nanoTime();
    for (int i = 0; i < times; i++)
        es.submit(r);
    es.shutdown();
    es.awaitTermination(1, TimeUnit.MINUTES);
    long time = System.nanoTime() - start;
    System.out.println("Average time to " + r + " was " + time / times / 10000 + " us");
}
+1

( )

if (nextSerialNumber >= Integer.MAX_VALUE)   // ;

either print something or catch this exception when calling regular

0
source

Source: https://habr.com/ru/post/1786407/


All Articles