Skip to content

Instantly share code, notes, and snippets.

@sb8244
Created September 12, 2023 06:22
Show Gist options
  • Save sb8244/4ab8b164536bca76ec0aa75afde8efad to your computer and use it in GitHub Desktop.
Save sb8244/4ab8b164536bca76ec0aa75afde8efad to your computer and use it in GitHub Desktop.
public class ImmutableCounter {
private final int counter;
public ImmutableCounter(int num) {
this.counter = num;
}
public int getCount() {
return this.counter;
}
public ImmutableCounter increase() {
return new ImmutableCounter(this.counter + 1);
}
}
import org.junit.jupiter.api.Test;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
import static org.junit.jupiter.api.Assertions.*;
class ImmutableCounterTest {
@Test
void immutableCounterIsImmutable() {
ImmutableCounter immutableCounter = new ImmutableCounter(0);
assertEquals(1, immutableCounter.increase().getCount());
assertEquals(1, immutableCounter.increase().getCount());
assertEquals(2, immutableCounter.increase().increase().getCount());
}
@Test
void mutableCounterIsNotImmutable() {
UnsafeCounter counter = new UnsafeCounter(0);
assertEquals(1, counter.increase());
assertEquals(2, counter.increase());
}
@Test
void unsafeCounterIsNotThreadSafe() throws InterruptedException {
UnsafeCounter counter = new UnsafeCounter(0);
ReentrantLock lock = new ReentrantLock();
// TODO: How can you use this lock to make the code safe?
// Hint: It's just like the lock on your home's door
// Explore: Why locks are difficult to manage in production systems
Runnable code = () -> {
for (int i = 0; i < 10000; i++) {
int startValue = counter.getCount();
counter.increase();
int currentValue = counter.getCount();
assertEquals(startValue + 1, currentValue);
}
};
Thread t1 = new Thread(code);
Thread t2 = new Thread(code);
AtomicInteger errorCounter = new AtomicInteger();
t1.setUncaughtExceptionHandler((Thread t, Throwable e) -> { errorCounter.incrementAndGet(); });
t2.setUncaughtExceptionHandler((Thread t, Throwable e) -> { errorCounter.incrementAndGet(); });
t1.start();
t2.start();
t1.join();
t2.join();
assertEquals(0, errorCounter.get());
}
/*
@Test
void immutableCounterIsThreadSafe() throws InterruptedException {
// TODO: We get an error with the current code. How do we get this code to work?
// Hint: because the counter is immutable we need reassignment.
ImmutableCounter counter = new ImmutableCounter(0);
Runnable code = () -> {
for (int i = 0; i < 10000; i++) {
int startValue = counter.getCount();
counter = counter.increase();
int currentValue = counter.getCount();
assertEquals(startValue + 1, currentValue);
}
};
Thread t1 = new Thread(code);
Thread t2 = new Thread(code);
t1.start();
t2.start();
t1.join();
t2.join();
}
*/
}
public class UnsafeCounter {
private int counter;
public UnsafeCounter(int num) {
this.counter = num;
}
public int increase() {
this.counter += 1;
return this.counter;
}
public int getCount() {
return this.counter;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment