I am wondering why the result is not 400 000. There are two threads why does it gets blocked?
class IntCell {
private int n = 0;
public int getN() {return n;}
public void setN(int n) {this.n = n;}
}
class Count extends Thread {
private static IntCell n = new IntCell();
#Override public void run() {
int temp;
for (int i = 0; i < 200000; i++) {
temp = n.getN();
n.setN(temp + 1);
}
}
public static void main(String[] args) {
Count p = new Count();
Count q = new Count();
p.start();
q.start();
try { p.join(); q.join(); }
catch (InterruptedException e) { }
System.out.println("The value of n is " + n.getN());
}
}
Why there is so problem with that?
Because the way you increment your variable is not an atomic operation indeed to increment it you:
Get the previous value
Add one to this value
Set a new value
They are 3 operations not done atomically you should either us a synchronized block or use an AtomicInteger instead.
With a synchronized block it would be something like:
synchronized (n) {
temp = n.getN();
n.setN(temp + 1);
}
With an AtomicInteger you will need to rewrite your code as next:
class IntCell {
private final AtomicInteger n = new AtomicInteger();
public int getN() {return n.get();}
public void incrementN(int n) {this.n.addAndGet(n);}
}
for (int i = 0; i < 200000; i++) {
n.incrementN(1);
}
The approach with an AtomicInteger is non blocking so it will be faster
When two threads access one object at the same time, they interfere with each other, and the result is not deterministic. For example, imagine that p reads the value of n and gets, say, 0, then q reads the same value and gets 0 too, then p sets value to 1 and q also sets it to 1 (because it still thinks that it has value 0). Now the value of n is increased by 1, even though both counters "incremented" it once. You need to use synchronized block to make sure the counters won't interfere with each other. See https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html for more.
The problem here is that you allow for race conditions. Consider the block inside the loop:
temp = n.getN();
n.setN(temp + 1);
The code context switch between the time you get the current N and by the time you increment it, making you set an "old" value. One way around this is to ensure the inner part of the loop runs in a synchronized block:
for (int i = 0; i < 200000; i++) {
synchronized (n) { / Here!
temp = n.getN();
n.setN(temp + 1);
}
}
Related
I'm new to programming and been studying threads for some time now.
So, the following code should give an output of:
one 98098
two 98099
and it does sometimes.
When I try to run it for a couple of times, it gives different outputs. I can understand that the JVM controls the threads and I can't directly affect it, but some of the outputs are less than 98,000 even though the for loop is adding 1000 for 98 times. How is this happening? Can a thread leave lines behind? Or did I do something wrong (note: the expected output sometimes shows on the screen, but not always)
public class TestThreads {
public static void main(String [] args) {
ThreadOne t1 = new ThreadOne();
Thread one = new Thread(t1);
ThreadTwo t2 = new ThreadTwo();
Thread two = new Thread(t2);
one.start();
two.start();
}
}
class Accum {
private int counter = 0;
private static Accum a = new Accum();
private Accum() {
}
public static Accum getAccum() {
return a;
}
public int getCount() {
return counter;
}
public void updateCounter(int add) {
counter += add;
}
}
class ThreadOne implements Runnable {
Accum a = Accum.getAccum();
public void run() {
for(int x=0; x < 98; x++) {
a.updateCounter(1000);
try {
Thread.sleep(50);
} catch(InterruptedException ex) { }
}
System.out.println("one "+a.getCount());
}
}
class ThreadTwo implements Runnable {
Accum a = Accum.getAccum();
public void run() {
for(int x=0; x < 99; x++) {
a.updateCounter(1);
try {
Thread.sleep(50);
} catch(InterruptedException ex) { }
}
System.out.println("two "+a.getCount());
}
}
Basically, your updateCounter method isn't thread-safe. If it's called from two threads at the same time, you can lose information.
Let's rewrite it to make it more obvious why that's the case:
public void updateCounter(int add) {
// Fetch
int originalValue = counter;
// Compute
int newValue = originalValue + add;
// Store
counter = newValue;
}
Imagine what happens if two threads come into the method at the same time. We'll pretend that there's some "total ordering" of what happens - the reality is more complex than that, but even the simplified form shows the problem. Suppose counter has a value of 5 to start with, and on thread x we're calling updateCounter(3) and on thread y we're calling updateCounter(4). We could imagine this sequence of events:
Thread x executes the "fetch" operation: originalValue = 5 (local variable, unaffected by thread y)
Thread y executes the "fetch" operation: originalValue = 5
Thread x executes the "compute" operation: newValue = 8
Thread y executes the "compute" operation: newValue = 9
Thread x executes the "store" operation: counter = 8 (note that newValue in thread x is separate to the one in thread y)
Thread y executes the "store" operation: counter = 9
So we end up with the value of counter being 9... as if the updateCounter(3) call had never taken place. If the last two operations happened in the reverse order, then counter would be 8 instead.
The way to fix this is to use the AtomicInteger class which is designed specifically to make operations like this atomic:
class Accum {
private final AtomicInteger counter = new AtomicInteger(0);
private static Accum a = new Accum();
private Accum() {
}
public static Accum getAccum() {
return a;
}
public int getCount() {
return counter.get();
}
public void updateCounter(int add) {
counter.addAndGet(add);
}
}
My goal is to understand how the volatile keyword works.
My expected result: The assertEquals did not fail.
My actual result: The assertEquals fail. (sometimes the actual count value are between 9991 to 9999).
I am assuming this happens because of the increment operators / count++ equals to
public void increment() {
int temp = count;
count = temp + 1;
}
and considering that, the temp attribute is stored thread-locally. Am I true?
Counter.java
public class Counter implements Runnable {
private volatile int count = 0;
public int getCount() { return count; }
public void increment() { count++; }
#Override
public void run() { increment(); }
}
CounterTest.java
public class CounterTest {
#Test
void increment() {
ExecutorService service = Executors.newFixedThreadPool(10);
Counter counter = new Counter();
for (int i = 0; i < 10000; i++) {
service.execute(counter);
}
service.shutdown();
service.awaitTermination(1, TimeUnit.SECONDS);
assertEquals(10000, counter.getCount());
}
}
My goal is to understand how the volatile keyword works
If that is your goal, then start looking at the JLS and the guarantees that volatile offers. volatile is not about atomic operations, i.e.: count++; is not atomic. As such, this :
assertEquals(10000, counter.getCount());
can fail, at any point in time.
volatile is about what some thread is supposed to "observe" when it has observed a written value to that variable, by another thread. There are many, literally many examples of what this means, probably the most famous one is this. Start there and build your knowledge up to the JLS.
Basically I have a method that I want to synchronize (only let one thread in at a time), however I'm not allowed to use the synchronized keyword for this particular practice. Instead, I decided to create a semaphore and just set the value to 1, therefore acting like a mutually exclusive lock (which is what I believe the synchronized keyword does right?).
So basically, my Semaphore class looks like this:
import java.util.*;
public class Semaphore
{
private int count = 0;
public Semaphore (int init_val) {
count = init_val;
}
public synchronized void P() {
count = count - 1;
while(count < 0) {
try {
wait();
} catch(InterruptedException e) {
}
}
}
public synchronized void V() {
count = count + 1;
notifyAll();
}
}
And I'm using it inside the method I want to synchronize like this (just an example):
Semaphore s = new semaphore(1);
int x = 0;
public void add() {
s.P()
int x = x + 1;
System.out.println(x);
s.V()
}
I have 100 threads calling the add method, but for some reason the value of x is concurrent, but not going up in order (race condition). I'm not sure what I'm doing wrong, any advice?
I read now Thinking in Java, chapter about atomicity and visibility. There is an example I don't understand.
public class SerialNumberGenerator {
private static volatile int serialNumber = 0;
public static int nextSerialNumber() {
return serialNumber++;
}
}
class CircularSet {
private int[] array;
private int len;
private int index = 0;
public CircularSet(int size) {
array = new int[size];
len = size;
for (int i = 0; i < size; i++) {
array[i] = -1;
}
}
synchronized void add(int i) {
array[index] = i;
index = ++index % len;
}
synchronized boolean contains(int val) {
for (int i = 0; i < len; i++) {
if (array[i] == val)
return true;
}
return false;
}
}
public class SerialNumberChecker {
private static final int SIZE = 10;
private static CircularSet serials = new CircularSet(1000);
private static ExecutorService exec = Executors.newCachedThreadPool();
static class SerialChecker implements Runnable {
#Override
public void run() {
while (true) {
int serial = SerialNumberGenerator.nextSerialNumber();
if (serials.contains(serial)) {
System.out.println("Duplicate: " + serial);
System.exit(0);
}
serials.add(serial);
}
}
}
public static void main(String[] args) throws Exception {
for (int i = 0; i < SIZE; i++) {
exec.execute(new SerialChecker());
}
}
}
example output:
Duplicate: 228
I don't understand how is it possible. Even method nextSerialNumber() is not synchronized and all thread generate different values each thread has own value of serial and each are different. So how is it possible to find duplicate. I cannot imagine of threads execution.
This example shows the post-increment operator is not atomic and not thread-safe.
What happens in this code is:
many (up to 100) threads are started, each executing the same code
in an infinite loop:
an unsynchronized method nextSerialNumber is called, which returns the result of the post-increment operator called on a static variable
a synchronized method contains is called, which checks if the returned value exists in the underlying collection
if yes, the program is terminated
if not, the value is added to the underlying collection
If the post-increment operation was thread-safe then the program would never print "Duplicate" and would never terminate,
since every thread would be getting a different serial number value. This is not the case as two threads
might get exactly the same serial number value.
I use the int array.
I use that method to fill indexes in array.
public void makeSelectionOfGivenNumber(int number) throws InterruptedException
{
if (this.table[number]!= 0)
{
int multiple;
multiple = number + number;
while (multiple <= upperRange)
{
this.table[multiple] = 0;
multiple += number;
}
}
}
For example, one thread starts from 2 and eliminates all multiples, a second thread starts from 5 and makes the same activities. In some case the simultaneously the value in index 10 (in both cases are multiples). How to use in this case semaphores or other tools to lock that only one thread has access on particular index, not the whole array. I want that these two threads would work in parallel on the same table.
I think You need to create an additional array of locks (ReadWriteLock, a dimension of the array is how you want) and before each attempt to read/change in the target array to take a lock on reading or on writing the element into the array. To take the lock need to calculate an index from the required index of target array and the capacity of the additional array.
Maybe I'm not quite correctly understood the task
public class SomeTask {
private final ReadWriteLock[] locks = locks(5);
private int[] table;
private int upperRange;
public SomeTask(int[] table, int upperRange) {
this.table = table;
this.upperRange = upperRange;
}
public void makeSelectionOfGivenNumber(int number) {
if (this.table[number] != 0) {
int multiple;
multiple = number + number;
while (multiple <= upperRange) {
ReadWriteLock lock = getLock(multiple);
try {
lock.writeLock().lock();
this.table[multiple] = 0;
} finally {
lock.writeLock().unlock();
}
multiple += number;
}
}
}
private ReadWriteLock getLock(int number) {
return locks[(locks.length - 1) & number];
}
private ReadWriteLock[] locks(int size) {
ReadWriteLock[] result = new ReadWriteLock[size];
for (int i = 0; i < size; i++) {
result[i] = new ReentrantReadWriteLock();
}
return result;
}