• Tidak ada hasil yang ditemukan

Application-level concurrency: Optimistic Concurrency Control

N/A
N/A
Protected

Academic year: 2023

Membagikan "Application-level concurrency: Optimistic Concurrency Control"

Copied!
9
0
0

Teks penuh

(1)

color

Application-level concurrency: Optimistic Concurrency Control

Summary of Friday’s lecture We learned about:

• Representing tasks that return values using implementations ofCallable.

• Accessing returned values and controlling task execution usingFutures.

• FutureTasks and their implementations.

• RunningFutureTasks.

We have seen how

• Creating and destroying threads is expensive.

• Thread poolsreduce this overhead by reusing existing threads.

• ExecutorServiceis a class that manages thread pools.

• Any Callableor Runnable task can be submitted to an Executor or a ExecutorService.

Next step, optimistic concurrency control!

Compare-and-set

• Typical computer architectures offer atomicmachine code instructions specifically addressed at managing concurrency.

• One such instruction is compare-and-set (also compare-and-swap or CAS):

1. atomicallycompares the value at a memory address to a given ex- pected value.

2. If these are equivalent, sets the value at the memory address to an updated value.

• These hardware instructions can be used to efficiently implement synchro- nization primitives, such as locks.

• These instructions can also be used to develop optimisticor lock-free algorithms.

• In some low-contention scenarios, these run faster than lock-based solu-

(2)

Compare-and-set

Conceptually, an integer compare-and-set instruction is equivalent to the following method:

public boolean synchronized compare_and_set(

int* address, int expect, int update) { boolean asExpected = (*address == expect);

if (asExpected)

*address = update;

return asExpected;

}

Here “*” is C-like notation indicating a pointer dereference:

• addressis a memory location (pointer).

• *addressis the contents of that memory location.

Compare-and-set

• The CAS instruction involvesfourdistinct elements:

compare_and_set(int* address, int expect, int update)

• Actual instruction name differs between architectures. For x86 machines the instruction isCMPXCHG(compare and exchange).

Locking using compare-and-set

The atomicity of the CAS operation can be used to create a simple lock as follows:

• Suppose the value of*addressis an integer representing the thread which holds the lock, with zero meaning that no thread has acquired the lock.

(3)

• The following operation will acquire the lock for thread 1, provided the lock is free:

boolean success = compare_and_set(address, 0, 1);

• If the lock is already held by thread 2, the CAS will fail and returnfalse.

• Otherwise, the CAS will succeed, meaning that contents of*addresswill be set to 1 and the CAS will return true.

Locking using compare-and-set

• The following pseudo-code uses CAS to implement a lock acquisition at- tempt that blocks the execution of the thread 1 until the lock is acquired.

while (!compare_and_set(address, 0, 1));

• This is reminiscent of the way in which reentrantLock.lock() blocks execution untilreentrantLockis able to be acquired.

• This particular design is known as aspin lock (it keeps “spinning” until the lock is acquired).

The atomic package in Java

The Java packagejava.util.concurrent.atomic offers a set of “atomic”

classes:

• These wrap around a variety of Java types.

• They ensure thread-safe lock-free access.

• They use efficient hardware compare-and-set instructions.

The atomic package in Java

Excerpts from thejava.util.concurrent.atomicclasses:

• AtomicInteger(wraps an integer)

• AtomicLong(wraps a long integer)

• AtomicReference(wraps an object reference - i.e. an object pointer)

• AtomicStampedReference(wraps a pair consisting of an object reference plus an integer stamp)

(4)

AtomicInteger methods

AtomicInteger has all of the thread-safe methods required by our thread-safe counter, and more. In particular:

boolean compareAndSet(int expect, int update)

• Atomically sets the value to the given updated value if (and only if) the current value is the same as the expected value.

• herevalueis the value of the private integer wrapped by thisAtomicInteger.

• This method istypicallybased on a hardware compare-and-set instruction, so it is thread-safe and lock-free.

AtomicInteger methods The call

atomicInt.compareAndSet(expect, update);

whereatomicIntis an instance of AtomicInteger is equivalent to the earlier pseudo-code

compare_and_set(address_of(value), expect, update)

where we assume that address of(value)returns the memory address of the integer value wrapped by thisAtomicInteger.

AtomicInteger pseudo-code

The as far as itscompareAndSet()method is concerned, theAtomicInteger class might be described by the following pseudo-code:

public class AtomicInteger { int value;

public boolean synchronized compareAndSet(

int expect, int update) {

boolean asExpected = (this.value == expect);

if (asExpected)

this.value = update;

return asExpected;

}

Other AtomicInteger methods

These methods are also thread-safe and lock-free:

• int get(): Gets the currentvalue.

• int decrementAndGet(): Atomically decrements by one then retrieves the currentvalue.

(5)

• int incrementAndGet(): Atomically increments by one then retrieves the currentvalue.

• int getAndDecrement(): Atomically retrieves and then decrements by one the currentvalue.

• int getAndIncrement(): Atomically retrieves and then increments by one the currentvalue.

Note

• Methods starting withgetreturn the valuebeforethe update

• Methods ending withgetreturn the valueafter the update

Recap: Counter class

Consider again the followingCounterclass.

public class Counter { protected int c = 0;

public void increment() { c++;

}

public void decrement() { c--;

}

public int getValue() { return c; } }

Counter.java

• Can we make this thread-safe without synchronization/locking?

Lock-free thread-safe Counter class Yes we can!

import java.util.concurrent.atomic.AtomicInteger;

public class CounterLockFree extends Counter {

protected AtomicInteger cAtomic = new AtomicInteger(0);

public void increment() { cAtomic.incrementAndGet();

}

public void decrement() { cAtomic.decrementAndGet();

}

public int getValue() { return cAtomic.get();

(6)

AtomicInteger implementations

We have learned thatcompareAndSet()is based on the hardware compare- and-set (CAS) instruction.

What about the other methods, such asincrementAndGet()?

There are several possible implementations:

• based on compareAndSet

• based on other atomic hardware instructions (if available) Example: incrementAndGet implementation

This is a typical optimistic lock-free approach:

public final int incrementAndGet() { while (true) {

int current = this.value;

int next = current + 1;

boolean ok = compareAndSet(current, next); // Note 1

if (ok)

return next;

// Note 2 }

}

Note 1: IfAtomicInteger’s privatevalue has not been changed (by another thread) then this is updated to the next value andokis set totrue.

Note 2: Otherwise, we retry the procedure until success.

AtomicInteger implementations

• Alternatively, the methodincrementAndGetcan be based on the hardware lock prefixavailable for some instructions on modern Intel processors.

• A few instructions which, if modified with a lock prefix, run atomically on Intel processors include: ADD, SUB, INC, DEC.

• When modified with the lock prefix, these instructions are typically re- named LOCK ADD, LOCK SUB, LOCK INC, LOCK DEC.

(7)

The ABA problem Related Question

Why do we need theAtomicStampedReferenceclass?

Answer

If it finds the expected value, compare-and-set cannot determine whether

• The value referenced by the memory address has never been changed (was A and it is still the same A), or

• the value actually has been changed, but subsequently restored to its pre- vious value (was A, changed to B, then back to A).

This is known asthe ABA problem.

An ABA scenario

AtomicInteger X = new AtomicInteger(10);

Thread 1

boolean a = X.compareAndSet(10, 20);

// ...

// ...

boolean b = X.compareAndSet(20, 30);

Thread 2 // ...

boolean a = X.compareAndSet(20, 40);

boolean b = X.compareAndSet(40, 20);

// ...

With “bad” interleaving, allcompareAndSet()calls succeed andXtakes the values 10,20,40,20,30 successively.

The ABA problem

Stamped references can be used to solve the ABA problem:

• By atomically associating a “stamp” number to each reference.

• Stamp numbers should be monotonically incremented at each update.

• Thus, even if a reference looks unchanged, its stamp number will be dif- ferent if the reference was updated.

• In this case, the compareAndSet() method will fail, as the comparison

(8)

The ABA problem: concrete example

Consider the following basic LIFO stack implementation:

public classStack {

public AtomicReference<Item> top=newAtomicReference<Item>();

public void push(Item newTop) { do{

newTop.prev =top.get();

}while(!top.compareAndSet(newTop.prev,newTop));

}

public Item pop() { Item oldTop,newTop;

do{

oldTop =top.get();

newTop =oldTop.prev;

}while(!top.compareAndSet(oldTop,newTop));

oldTop.prev =null;

returnoldTop;

} }

Stack.java

• Is this implementation thread-safe?

The ABA problem: example

The ABA problem: example solution

(9)

public classStackStamped {

public AtomicStampedReference<Item>top =

newAtomicStampedReference<Item>(null, 0);

public int[] stampHolder=new int[1];

// ... push() ...

public Item pop() { Item oldTop,newTop;

intexpectedStamp,newStamp;

do{

oldTop =top.get(stampHolder);

newTop =oldTop.prev;

expectedStamp =stampHolder[0];

newStamp =expectedStamp + 1;

}while(!top.compareAndSet(oldTop,newTop,expectedStamp, newStamp));

oldTop.prev =null;

returnoldTop;

} }

StackStamped.java

Solved usingAtomicStampedReference!

Summary

Today we have:

• Learned how to define an optimistic concurrency control strategy.

• Discussed where such strategies are useful.

• Learned about the compare-and-set (or compare-and-swap or CAS) and how to describe its operation using pseudo-code.

• Learned what theAtomicclasses in Java’s atomic package do, where they can be used.

• Talked about the ABA problem and seen examples of where it can arise.

• Discussed the use of stamped references to address this problem.

Referensi

Dokumen terkait

previous research mentioned the skills and profile of teachers, but not exactly studied the EFL teacher’s need. Therefore, speaking skills are useful for learners when

2010 menyatakan bahwa self- transcendence dan work meaningfulness merupakan dua hal yang tidak bisa saling terpisahkan karena perasaan bahwa bekerja merupakan hal yang bermakna dapat