This:
if (var) {
var = false;
}
Versus this:
var = false;
Is there a speed difference?
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.
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:
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.
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.
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.
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
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.).
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.