Are these methods getNewId() & fetchIdsInReserve() thread safe ?
public final class IdManager {
private static final int NO_OF_USERIDS_TO_KEEP_IN_RESERVE = 200;
private static final AtomicInteger regstrdUserIdsCount_Cached = new AtomicInteger(100);
private static int noOfUserIdsInReserveCurrently = 0;
public static int getNewId(){
synchronized(IdManager.class){
if (noOfUserIdsInReserveCurrently <= 20)
fetchIdsInReserve();
noOfUserIdsInReserveCurrently--;
}
return regstrdUserIdsCount_Cached.incrementAndGet();
}
private static synchronized void fetchIdsInReserve(){
int reservedInDBTill = DBCountersReader.readCounterFromDB(....); // read column from DB
if (noOfUserIdsInReserveCurrently + regstrdUserIdsCount_Cached.get() != reservedInDBTill) throw new Exception("Unreserved ids alloted by app before reserving from DB");
if (DBUpdater.incrementCounter(....)) //if write back to DB is successful
noOfUserIdsInReserveCurrently += NO_OF_USERIDS_TO_KEEP_IN_RESERVE;
}
}
No.
If 21 threads comes in here
synchronized(IdManager.class){
if (noOfUserIdsInReserveCurrently <= 20)
fetchIdsInReserve();
noOfUserIdsInReserveCurrently--;
}
and wait while another 180 threads proceed through the top and through the line below, then by the time the 21st thread reaches the line below, there will be no user ids in reserve when the 21st thread from the first group calls
return regstrdUserIdsCount_Cached.incrementAndGet();
EDIT:
Here's the initial state on class load:
regstrdUserIdsCount_Cached = 100
noOfUserIdsInReserveCurrently = 0
Let's assume that the write back to the DB is always successful. If it isn't, this code is clearly broken, because it still allocates an ID in that case.
The first thread comes through, and calls fetch because there are no ids in reserve.
regstrdUserIdsCount_Cached = 100
noOfUserIdsInReserveCurrently = 0
assuming the DB returns 100 as the initial ID, after the method completes without contention
regstrdUserIdsCount_Cached = 101
noOfUserIdsInReserveCurrently = 199
Now, let's assume 178 more threads go through without contention
regstrdUserIdsCount_Cached = 279
noOfUserIdsInReserveCurrently = 21
if that thread is preempted by another that comes through after it exits the synchronized block but before it decrements the atomic int, the preempting thread will trigger a fetch.
Since noOfUserIdsInReserveCurrently has not been decremented by the thread that was pre-empted,
(noOfUserIdsInReserveCurrently + regstrdUserIdsCount_Cached.get() != reservedInDBTill)
will be false.
Assuming that exception indicates a failure mode, we have a failure during one interleaving that is not thrown during other-interleavings. Therefore, the code is not thread-safe.
The solution is to consistently access regstrdUserIdsCount_Cached inside the critical section. In that case, it need not be an atomic int, but can simply be a non-final int.
You the field noOfUserIdsInReserveCurrently is not accessed from anywhere else, then yes - access to it is thread-safe.
P.S. if fetchIdsInReserve is called only from inside the synchronized
block in the getNewId method, then you don't have to make the method synchronized.
UPDATE: as long as the question was edited, now it is not thread-safe. You have to have the return statement in the first method INSIDE the synchronized block. And it doesn't have to be an AtomicInteger, it can be just a simple int in this case.
Here is an example test to show it is thread safe. Replace the AtomicInteger with an int and get rid of the syncs and the test should fail.
public static void main(String... arg) throws Exception {
final int loops = 1042;
for (int l = 0; l != loops; l++) {
reset(); // add this method to your class to reset the counters
final int maxThreads = 113;
final ArrayList<String> checker = new ArrayList<String>();
final CountDownLatch cl1 = new CountDownLatch(maxThreads);
final CountDownLatch cl2 = new CountDownLatch(maxThreads);
for (int x = 0; x != maxThreads; x++) {
Thread thread = new Thread(new Runnable() {
public void run() {
cl1.countDown();
try {
cl1.await(); // stack all threads here
} catch (InterruptedException e) {
e.printStackTrace();
}
int id = getNewId();
synchronized(checker) {
checker.add("" + id);
}
cl2.countDown();
}
});
thread.start();
}
cl2.await();
for (int x = 0; x != maxThreads; x++) {
String key = "" + (101 + x); // 1st ID value
if (!checker.contains(key)) {
System.out.println("Checker 1 FAIL - missing id=" + key);
} else {
checker.remove(key);
if (checker.contains(key)) {
System.out.println("Checker 2 FAIL - extra id=" + key);
}
}
}
for (int x = 0; x != checker.size(); x++) {
String key = "" + (101 + x);
System.out.println("Checker 3 FAIL - extra id=" + key);
}
}
}
Related
I am writing a thread safe counter. When I test and the threads go first one, then the second everything works correctly. But when threads enter the increment () method at the same time, the counter does not work properly. The reason is not clear, I am using atomic integer.
public class CASCount {
private final AtomicReference<Integer> count = new AtomicReference<>(0);
private AtomicInteger oldValue = new AtomicInteger(0);
private AtomicInteger newValue = new AtomicInteger(0);
public void increment() {
do {
oldValue.set(count.get());
System.out.println(oldValue + " old");
if (oldValue.get() == -1) {
throw new UnsupportedOperationException("Count is not impl.");
}
newValue.incrementAndGet();
System.out.println(newValue + " new");
} while (!count.compareAndSet(oldValue.get(), newValue.get()));
}
public int get() {
int result = -1;
result = count.get();
if (result == -1) {
throw new UnsupportedOperationException("Count is not impl.");
}
return result;
}
}
#Test
public void whenUseCASCount() throws InterruptedException {
CASCount count = new CASCount();
Thread one = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("one");
count.increment();
}
});
Thread two = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("two");
count.increment();
}
});
one.start();
two.start();
one.join();
two.join();
assertThat(count.get(), is(10));
}
its my decision
private final AtomicReference<Integer> count = new AtomicReference<>(0);
public void increment() {
int current, next;
do {
current = count.get();
next = current + 1;
} while (!count.compareAndSet(current, next));
}
public int get() {
return count.get();
}
TL;DR - Make your increment method synchronized.
Details - Even though you have atomic variables that you use, that does not mean that your class is thread safe. It's not safe because there can be (and are) race conditions between the checks and increments for your variables.
do {
oldValue.set(count.get());
System.out.println(oldValue + " old");
if (oldValue.get() == -1) {
throw new UnsupportedOperationException("Count is not impl.");
}
newValue.incrementAndGet(); <--- between here
System.out.println(newValue + " new");
} while (!count.compareAndSet(oldValue.get(), newValue.get())); <--- and here
A typical case of check-then-act race condition.
This happens because your atomic variables can be accessed by multiple threads and their shared state can mutate from one thread and not be seen in another.
To preserve state consistency, update related state variables in a single
atomic operation.
- Java Concurrency in Practice
Hence, we use intrinsic locks (built-in synchronized) to make the method safe when multiple threads access it. What happens is that the state of the atomic variables would not change because each thread will access the increment method one at a time.
I am doing a sample program with wait() and notify(), but when notify() is called, more than one thread is wakes up instead of one.
The code is:
public class MyQueue<T> {
Object[] entryArr;
private volatile int addIndex;
private volatile int pending = -1;
private final Object lock = new Object();
private volatile long notifiedThreadId;
private int capacity;
public MyQueue(int capacity) {
entryArr = new Object[capacity];
this.capacity = capacity;
}
public void add(T t) {
synchronized (lock) {
if (pending >= 0) {
try {
pending++;
lock.wait();
System.out.println(notifiedThreadId + ":" + Thread.currentThread().getId());
} catch (InterruptedException e) {
e.printStackTrace();
}
} else if (pending == -1) {
pending++;
}
}
if (addIndex == capacity) { // its ok to replace existing value
addIndex = 0;
}
try {
entryArr[addIndex] = t;
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("ARRAYException:" + Thread.currentThread().getId() + ":" + pending + ":" + addIndex);
e.printStackTrace();
}
addIndex++;
synchronized (lock) {
if (pending > 0) {
pending--;
notifiedThreadId = Thread.currentThread().getId();
lock.notify();
} else if (pending == 0) {
pending--;
}
}
}
}
public class TestMyQueue {
public static void main(String args[]) {
final MyQueue<String> queue = new MyQueue<>(2);
for (int i = 0; i < 200; i++) {
Runnable r = new Runnable() {
#Override
public void run() {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
queue.add(Thread.currentThread().getName() + ":" + i);
}
}
};
Thread t = new Thread(r);
t.start();
}
}
}
After some time, I see two threads being wake up by single thread. The output looks like:
91:114
114:124
124:198
198:106
106:202
202:121
121:40
40:42
42:83
83:81
81:17
17:189
189:73
73:66
66:95
95:199
199:68
68:201
201:70
70:110
110:204
204:171
171:87
87:64
64:205
205:115
Here I see 115 thread notified two threads, and 84 thread notified two threads; because of this we are seeing the ArrayIndexOutOfBoundsException.
115:84
115:111
84:203
84:200
ARRAYException:200:199:3
ARRAYException:203:199:3
What is the issue in the program?
What is the issue in the program?
You have a couple of problems with your code that may be causing this behavior. First, as #Holder commented on, there are a lot of code segments that can be run by multiple threads simultaneously that should be protected using synchronized blocks.
For example:
if (addIndex == capacity) {
addIndex = 0;
}
If multiple threads run this then multiple threads might see addIndex == capacity and multiple would be overwriting the 0th index. Another example is:
addIndex++;
This is a classic race condition if 2 threads try to execute this statement at the same time. If addIndex was 0 beforehand, after the 2 threads execute this statement, the value of addIndex might be 1 or 2 depending on the race conditions.
Any statements that could be executed at the same time by multiple threads have to be properly locked within a synchronized block or otherwise protected. Even though you have volatile fields, there can still be race conditions because there are multiple operations being executed.
Also, a classic mistake is to use if statements when checking for over or under flows on your array. They should be while statements to make sure you don't have the class consumer producer race conditions. See my docs here or take a look at the associated SO question: Why does java.util.concurrent.ArrayBlockingQueue use 'while' loops instead of 'if' around calls to await()?
I am learning java, and trying to summarize elements in table with multiple threads, but I am always getting wrong result.
I tried 4 different methods of threads synchronization and all of them failed. Everything is explained in the comments.
My result (bad):
Without threads: 4949937, 15ms
With threads: 4944805, 78ms
Maybe am I executing the System.out.println on summarizeT() too early? I mean before all the threads finish work. With .join() the summarizeT() method works good but. Is the .join() blocking the "main" thread until all other threads are finished?
Main class:
public class Main
{
static int size = 100000; //size of tab
static int length = 100; //each thread gets 100 elements of tab, thread 1 calculates sum from 0 to 99, thread 2 from 100 to 199 etc.
static int[] tab = new int[size];
static Random generator = new Random();
static void initialize()
{
for (int i = 0; i < size; i++)
tab[i] = generator.nextInt(100);
}
static int summarize() //summarize with only one thread
{
int sum = 0;
for (int i = 0; i < size; i++)
sum += tab[i];
return sum;
}
static int summarizeT() //summarize with more threads (size / length)
{
int threadsCounter = size/length;
int start = 0; //pointer to table from where each thread should start counting
int[] sum = new int[1]; //I am sharing the sum value between threads with table, not sure if it is best method to pass the value between them
sum[0] = 0;
Thread[] threads = new Thread[threadsCounter]; //nedeed for .join() test
for (int i = 0; i < threadsCounter; i++)
{
threads[i] = new Thread(new MyThread(tab, start, sum));
threads[i].start();
start += length; //moving the start pointer, next thread should start counting from next 100 indexes
}
/*for (int i = 0; i < threadsCounter; i++) // adding .join() solves the problem, but is it a good solution?
{
try {
threads[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}*/
return sum[0];
}
public static void main(String[] args)
{
initialize();
long start = Calendar.getInstance().getTimeInMillis();
System.out.println("Without threads: " + summarize() + ", " + (Calendar.getInstance().getTimeInMillis() - start) + "ms");
start = Calendar.getInstance().getTimeInMillis();
System.out.println("With threads: " + summarizeT() + ", " + (Calendar.getInstance().getTimeInMillis() - start) + "ms"); //giving wrong answer
}
}
MyThread class:
import java.util.concurrent.Semaphore;
public class MyThread extends Thread
{
int[] tab;
int[] sum;
int start;
MyThread(int tab[], int start, int sum[]) //in args: main table, starting index, value that is being shared between threads
{
this.tab = tab;
this.start = start;
this.sum = sum;
}
#Override
public void run()
{
int end = start + Main.length; //place where thread should stop counting
int temp = 0; //nedeed to sumarize the "subtable"
while (start < end)
{
temp += tab[start];
start++;
}
// Method 1
Semaphore semaphore = new Semaphore(1);
try {
semaphore.acquire();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
try
{
sum[0] += temp;
} catch (Exception e) {
} finally {
semaphore.release();
}
// Method 2
/*Object lock = new Object();
synchronized(lock)
{
sum[0] += temp;
}*/
// Method 3
/*synchronized(this)
{
sum[0] += temp;
}*/
// Method 4
//summarize(temp);
// Method 5 - no threads synchronization, works only when .join() is used, the same as other methods
//sum[0] += temp;
}
private synchronized void summarize(int value)
{
sum[0] += value;
}
}
Isn't the problem here that you create a lock object , or semaphore object, in each thread, rather than having one object that all threads synchronise on?
Each Thread creates is own Semaphore object ( for example ) so no other thread will ever contend with it. You need to create an object that ALL threads have access to and synchronise on that. You might consider synchronising on the array that you are writing the results in to itself.
There are some problems with your solution.
You should use AtomicInteger to hold results. that way you don't need to synchronize sum update.
BTW the way you synchronize is invalid. For semaphores to work you need to share same instance between all threads. And your try/catch/finally blocks are invalid. You should do acquire() and sum update in one try block, and release() in it's finally. That way you did it. It is possible that you'll do sum update even though acquire() failed.
Also you return from summarizeT() without waiting for threads to finish. You have to implement thread.join() logic or some other way to wait.
This is my code that sum variable 'res' by one 4*10^7 time using 4 threads:
class MathSin extends Thread {
public double a;
public MathSin(int degree) {
a = degree;
}
#Override
public void run() {
for (int i = 0; i < Math.pow(10., 7); i++)
MathThreads.res++;
}
}
class MathThreads {
public static double res = 0;
public static void main(String args[]) {
MathSin st = new MathSin(8);
MathSin ct = new MathSin(8);
MathSin tt = new MathSin(8);
MathSin qt = new MathSin(8);
st.start();
ct.start();
tt.start();
qt.start();
try { // wait for completion of all thread and then sum
st.join();
ct.join(); // wait for completion of MathCos object
tt.join();
qt.join();
System.out.println(res);
} catch (InterruptedException IntExp) {
}
}
}
and these are some of answers :
1.8499044E7
2.3446789E7
.
.
.
I expected get 3.0E7 but get another different answers.
how can fix this problem?
What is the problem?
You are observing race conditions while updating the static variable res.
MathThreads.res++
is equivalent to:
double tmp = MathThreads.res;
MathThreads.res = tmp + 1;
Now what happened if two threads reads at the same time a value for tmp, and both update res with tmp + 1? Well, one increment has simply been forgotten: res ends being tmp + 1 instead of being tmp + 1 + 1!
So with 4 threads updating res concurrently, you simply end up with an undefined behavior : it is impossible to predict the final value of res because of those race conditions. Two executions of the same code will give you different answers.
How to solve this issue?
To make your code thread-safe, you need to use a thread-safe structure for res: a structure that can be concurrently updated and accessed.
In your case, an AtomicLong seems the perfect choice:
public static AtomicLong res = new AtomicLong(0);
And in the run method:
for (int i = 0; i < Math.pow(10., 7); i++) {
MathThreads.res.incrementAndGet();
}
So, I ran a test and the results make no sense to me. Lets consider the following code:
ThreadStuffCounter counter_1 = new ThreadStuffCounter(1);
while(counter_1.doProceed) {
Thread.sleep(500);
Thread thread = new Thread(counter_1);
thread.start();
}
With the Runnable as follows:
package test;
public class ThreadStuffCounter implements Runnable {
public volatile boolean doProceed = true;
private int id = -1;
public volatile int i = -1;
public ThreadStuffCounter(int id) {
this.id = id;
}
#Override
public void run() {
for (i = 0; i < 10; i++) {
System.out.println("i = " + i + " in runnable id = " + id);
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
doProceed = false;
}
}
Only one instance of counter is shared between threads. It takes less time for another thread to start then even one increment to be made on the counter.doProceed should, as I understand never be set to false and the loop should continue indefinitely until I get an out of memory exception and cannot start any more threads.
How is it possible for the loop to exit?
EDIT: Modified code to make sure the answer below is correct.
package test;
public class ThreadStuffCounter implements Runnable{
public volatile boolean doProceed = true;
private int id = -1;
volatile int i = -1;
public ThreadStuffCounter(int id){
this.id = id;
}
#Override
public void run() {
i = 0;
while (i < 10){
System.out.println("i = " + i + " in runnable id = " + id +
"; from thead id = " + Thread.currentThread().getId());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
}
ThreadStuff.doProceed = false;
}
}
And
package test;
public class ThreadStuff {
public static volatile boolean doProceed = true;
public static void main (String[] args) throws InterruptedException{
ThreadStuffCounter counter_1 = new ThreadStuffCounter(1);
while(doProceed){
Thread.sleep(500);
Thread thread = new Thread(counter_1);
thread.start();
}
}
}
Also, it appears more then n threads are needed if you are running for i < n. You need however many, so that n threads increment at the same time.
When at least one of the threads executes the for loop and i value is greater or equal than 10, then doProceed variable will be false (yes, this may happen), and since it's volatile this will stop the execution of the while loop that creates and starts new threads. Then, is up to all the threads to just finish executing the code of the for loop and then finishing their execution. This seems to happen because the time to start a new thread in your environment is slower than the time for a current thread to finish its execution. Also, note that several threads may increase i value, which will accelerate the for loop execution.
Probably if you loop to a higher value (not tested) then this could generate an infinite loop and the application will break when there aren't enough resources to create and start new threads.
After some tests using the limit as 10, 50 and 1000. I noticed that when you have a bigger value, since lots of threads are created, all of them increase the value of i at the same time and i slowly starts to get closer to the limit value set in the for loop. Description of my current environment:
OS: Windows 7 Professional 64 bits
Processor: Intel(R) Core(TM) i5-2520M CPU # 2.50GHz (4 CPUs), ~2.5GHz
Ram: 8192MB