is checking a boolean faster than setting a boolean in java?

前端 未结 5 1291
死守一世寂寞
死守一世寂寞 2021-02-19 03:16

This:

if (var) {
    var = false;
}

Versus this:

var = false;

Is there a speed difference?

相关标签:
5条回答
  • 2021-02-19 03:31

    Here's another cheap "benchmark" (which almost doesn't deserve the term). To me, the results of Monkey Wrench's benchmark were not clearly speaking in regards to OP's question, so I thought I should put it here, too.

    Result (under these conditions, and quite few tests only): Checking a local boolean before writing it is better than writing it often if not necessary.

    public static void main(String[] args) {
    
        final Random r = new Random(0);
    
        boolean b = false;
        boolean decision;
    
        long startTime;
        long endTime;
    
        startTime = System.currentTimeMillis();
        for (long i = 0; i < 1000000000; i++) {
            decision = r.nextDouble() > 0.1; // Will be true MOST of the time.
    
            if (decision) {
    
                // if (!b) {
                    b = true;
                // }
    
            }
        }
        endTime = System.currentTimeMillis();
    
        System.err.println(endTime - startTime);
        System.err.println(b);
    
        System.exit(0);
    }
    
    With bluntly writing (ms):
    18139
    18140
    18196
    (18220)
    (18181)
    ----------
    Average of 3: 18158.333333333333333333333333333
    Average of 5: 18175.2
    
    
    With checking before writing (ms):
    18097
    18109
    18115
    (18129)
    (18133)
    ----------
    Average of 3: 18107
    Average of 5: 18116.6
    
    
    With checking, it only takes this % (3 samples): 99.71730151445617255621844882974
    With checking, it only takes this % (5 samples): 99.677582640080989480170782164708
    

    With checking, it takes about 99.7 % of the blunt-writing time. If the write would otherwise happen unnecessarily very often. In this crappy "benchmark", that is.

    0 讨论(0)
  • 2021-02-19 03:40

    Several things come into play, ultimate effect on actual performance is something you will need to measure for your use case. I assume this is a method you have found to happen A LOT:

    1. Branch prediction - if var is almost always false, which is what the code suggests, the branch predictor will be almost always right. If the field changes often then this is will become an often mispredicted branch and will be expensive.

    2. Read miss - If var is mostly read (and read A LOT) then avoiding changing without cause can help your software by not invalidating the cache line it sits on. If you write to it every other core who reads it (and anything on the same cache line) will need to get a fresh copy experiencing a read miss. This means the above method may be worth making slower for the sake of making reads have more consistent speed.

    3. Write cost vs. read cost - if var is volatile then it's write is a LoadStore barrier which is quite expensive. Reading a volatile (a LoadLoad barrier) is rather cheap by comparison (a cache hit for an often used and hardly changed value). This can make the branch very cheap by comparison.

    This is an optimization people make, and examples can be found in the JDK (IIRC), I assume you have a reason to consider it.

    0 讨论(0)
  • 2021-02-19 03:40

    I am late to the game on this one but I wrote this test class to answer a similar question.

    package SpeedTests;
    
    import java.text.NumberFormat;
    import java.util.Locale;
    
    public class BooleanSpeedTest {
    
        public static void main(String[] args) {
            boolean BoolTest = true;
            long LongLoop = 100000;
            long TrueLoopCount = 0;
            long FalseLoopCount = 0;
            long TimeTotal = 0;
    
            long startTime;
            long endTime;
    
            for(int intLoopA = 1; intLoopA < 6; intLoopA++) {
                LongLoop = LongLoop * 10;
                TimeTotal = 0;
                System.out.println("");
                System.out.print(
                        NumberFormat.getNumberInstance(Locale.US).format(LongLoop) + " - ");
    
                for(int intLoopM = 0; intLoopM < 20; intLoopM++) {
                    TrueLoopCount = 0;
                    FalseLoopCount = 0;
                    startTime = System.currentTimeMillis();
    
                    for(long LoopCount = 0; LoopCount < LongLoop; LoopCount++) {
                        if(!BoolTest) {
                            TrueLoopCount++;
                        }
                        else
                            FalseLoopCount++;   
                    }
                    endTime = System.currentTimeMillis();
                    System.out.print( (endTime - startTime) + "ms ");
                    TimeTotal += ((endTime - startTime) );    
                }
    
                System.out.print(" AVG: " + (TimeTotal/20));
            }
        }
    }
    

    My results: Avg time/billion (ms) Notes Time Per Loop

    if(BoolTest)                    443                     When False      0.00000443
    if(BoolTest)                    443                     When True
    
    if(BoolTest == false)           443                     When False
    if(BoolTest == false)           442                     When True
    
    if(!BoolTest)                   438                     When False      
    if(!BoolTest)                   441                     When True
    
    (BoolTest ? Var++ : Var--)      435                     When True
    (BoolTest ? Var++ : Var--)      435                     When False
    
    0 讨论(0)
  • 2021-02-19 03:41

    The "speed difference," if any, will depend entirely on the JVM. Any decent compiler should be able to optimize away the test, at which point the two are identical.

    Exception: If var is declared volatile the conditional version will always be slower.

    In any case, if performance is critical, the best option is to measure it under expected conditions (machine, system, JVM, typical load, etc.).

    0 讨论(0)
  • 2021-02-19 03:46

    The first code contains a comparison, so your compiler maybe generate a java bytecode that looks like:

      public static void main(java.lang.String[]);
        Code:
           0: iconst_1      
           1: istore_1      
           2: iload_1       
           3: ifeq          8
           6: iconst_0      
           7: istore_1      
           8: return    
    

    For the second code the generated bytecode is shorter because the comparison is missing:

      public static void main(java.lang.String[]);
        Code:
           0: iconst_1      
           1: istore_1      
           2: iconst_0      
           3: istore_1      
           4: return      
    

    The virtual machine needs more time for executing 8 commands in the first example than 4 commands in the second one. Although this difference should not be to high the second code is more clearly.

    Put your code in a simple main method and compile the class. Then run a command prompt and change to java/bin directory. To disassemble your class call javap -c path/to/YourClass.class >> path/to/bytecode.txt. bytecode.txt will contain the java bytecode of your class.

    0 讨论(0)
提交回复
热议问题