Introduction to the Java Memory Model
June 10th, 2010Yesterday, I gave at work a swift introduction to the JMM. Here.
Yesterday, I gave at work a swift introduction to the JMM. Here.
Proposed in Mathematics: A Very Short Introduction. Given the following rules:
A1 Commutative law for addition:
A2 Associative law for addition:
A3 Additive identity:
A4 Additive inverse:
A5 Cancellation law for addition:
M1 Commutative law for multiplication:
M2 Associative law for multiplication:
M3 Multiplicative identity:
M4 Multiplicative inverse:
M5 Cancellation law for multiplication:
D Distributive law:
Say we need to swap the values of two variables, a and b. This is a classic problem in programming and it can be accomplished in a few ways.
Using a temporary variable
This is the straightforward method; just use a temporary variable to avoid losing one of the variable values:
1 2 3 | temp = a a = b b = temp |
Accumulating one of the values
Use one of the variables to temporarily keep track of both variable values:
1 2 3 | a = a + b b = a - b a = a - b |
Using Exclusive-OR (XOR)
The exclusive-or binary operator takes two bits and returns 1 only if both values differ, 0 if equal:
| A | B | A XOR B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
The bitwise exclusive-or operator (^) will apply the exclusive-or operation on every pair of bits of the inputs.
01100110 ^ 01011110 -------- 00111000
Three interesting properties, given A, B = {0, 1}:
The third property requires further explanation. On the one hand, if B is 0 then, by 1), applying XOR B twice to A returns A itself. On the other, if B is 1 then we are flipping A twice by 2), which winds up returning A itself.
We base our last method of swapping two (integer) variables on those three properties:
1 2 3 4 5 6 | swap (A, B) { A = A ^ B; B = B ^ A; A = B ^ A; } |
More formally, the computation:
1 2 3 | A = A ^ B; B = B ^ A; A = B ^ A; |
is equivalent to:
1 | B = B ^ (A ^ B) = (A ^ B) ^ B = A |
At this point, B has the original value of A, therefore:
1 | A = A ^ (A ^ B) = (B ^ A) ^ A = B |
This last method is the most performant among them all.
Question
Now that we have sifted through these three methods of swapping two variables, question: which is the main advantage of the first over the others?
Given the following implementation of the Ackermann’s Function:
1 2 3 4 5 6 | (define (A x y) (cond ((= y 0) 0) ((= x 0) (* 2 y)) ((= y 1) 2) (else (A (- x 1) (A x (- y 1)))))) |
What are the evaluations of these expressions:
1 | (A 1 10) |
Value: 1024
1 | (A 2 4) |
Value: 65536
1 | (A 3 3) |
Value: 65536
What are the mathematical counterparts of these procedures:
1 | (define (f n) (A 0 n)) |
corresponds to:
1 2 3 4 5 6 7 8 | (define (g n) (A 1 n)) (A 0 (A 1 (- n 1)) (A 0 (A 0 (A 1 (- n 2)))) (A 0 (A 0 (A 0 (A 1 (- n 3))))) . . . |
corresponds to:
1 2 3 4 5 6 7 8 9 | (define (h n) (A 2 n)) (A 2 n) (A 1 (A 2 (- n 1))) (A 1 (A 1 (A 2 (- n 2)))) (A 1 (A 1 (A 1 (A 2 (- n 3))))) . . . |
At some step i, the most inner combination in the form (A 2 (- n i)) will evaluate to 2 cause n-i=1. (A 1 x) is 2^x by the definition of g(n), and there will be n evaluations of such combination, resulting in:
This can be also expressed as a recurrence:
Evaluate (+ 4 5) using the following procedure definition:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | (define (+ a b) (if (= a 0) b (inc (+ (dec a) b)))) (+ 4 5) (inc (+ (dec 4) 5)) (inc (+ 3 5)) (inc (inc (+ (dec 3) 5))) (inc (inc (+ 2 5))) (inc (inc (inc (+ (dec 2) 5)))) (inc (inc (inc (+ 1 5)))) (inc (inc (inc (inc (+ (dec 1) 5))))) (inc (inc (inc (inc (+ 0 5))))) (inc (inc (inc (inc 5)))) (inc (inc (inc 6))) (inc (inc 7)) (inc 8) 9 |
This is a linear recursive process.
Now, use the following definition instead to evaluate the same combination:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | (define (+ a b) (if (= a 0) b (+ (dec a) (inc b)))) (+ 4 5) (+ (dec 4) (inc 5)) (+ 3 6) (+ (dec 3) (inc 6)) (+ 2 7) (+ (dec 2) (inc 7)) (+ 1 8) (+ (dec 1) (inc 8)) (+ 0 9) 9 |
This is an linear iterative process.