I was reading about AtomicInteger and how its operations are atomic and how these properties make it useful for multithreading.
I wrote the following program to test the same.
I am expecting the final size of the set should be 1000, since each thread loops 500 times and assuming each time a thread calls getNext() it should get a unique number.
But the output is always less than 1000. What am i missing here?
public class Sequencer {
private final AtomicInteger i = new AtomicInteger(0);
public int getNext(){
return i.incrementAndGet();
}
public static void main(String[] args) {
final Sequencer seq = new Sequencer();
final Set<Integer> set = new HashSet<Integer>();
Thread t1 = new Thread(new Runnable() {
#Override
public void run() {
for (int i=0; i<500; i++)
set.add(seq.getNext());
}
},"T1");
t1.start();
Thread t2 = new Thread(new Runnable() {
#Override
public void run() {
for (int i=0; i<500; i++)
set.add(seq.getNext());
}
},"T2");
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(set.size());
}
}
You are missing that HashSet is not thread-safe. In addition the properties of a set would erase all duplicated numbers, so your test would fail if AtomicInteger was not thread-safe.
Try using a ConcurrentLinkedQueue instead.
Edit: Because it has been asked twice: Using a synchronized set works, but it destroys the idea behind using a lock-free algorithm like the Atomic-classes. If in your code above you replace the set with a synchronized set, then the threads will have to block each time add is called.
This will effectively reduce your application to single-threaded, because the only work done happens synchronized. Actually it will even be slower than single-threaded, because synchronized takes its toll as well. So if you want to actually utilize threading, try to avoid synchronized at all cost.
HashSet is not thread safe so you are facing problem.You can use Vector or any collection class which is thread safe or run two thread sequentially if you stricly need to use HashSet.
t1.start();
t1.join();
t2.start();
t2.join();
As mentioned in several answers, it fails due to HashSet not being thread safe.
First, lets verify for the sake of your test, that AtomicInteger is indeed thread-safe then proceed to see why your test failed. Modify your test slightly. Use two hashsets, one for each thread. Finally, after joins, merge the second set into the first, by iterating over the second and adding it to the first which will eliminate duplicates(set property). Then do a count on the first set.
The count will be what you expect. This proves that it is HashSet that is not thread safe and not the AtomicInteger.
So lets look at what aspect is not thread safe. You're doing onlyf add()s, so clearly add() is the operation that is not thread safe causing the loss of numbers. Lets look at an example pseudo-code non-thread safe HashMap add() that would lose numbers(this is obviously not how it implemented, just trying to state one way in which it could be non-thread safe):
class HashMap {
int valueToAdd;
public add(int valueToAdd) {
this.valueToAdd = valueToAdd;
addToBackingStore(this.valueToAdd);
}
}
If multiple threads call add() and they all reach the addToBackingStore() after they've changed this.valueToAdd, only the final value of valueToAdd is added, all other values are overwritten and lost.
Something similar to this is probably what happened in your test.
Try do it in that way using Collections synchronized.
public class Sequencer {
private final AtomicInteger i = new AtomicInteger(0);
public static void main(String[] args) {
final Sequencer seq = new Sequencer();
final Set<Integer> notSafe = new HashSet<Integer>();
final Set<Integer> set = Collections.synchronizedSet(notSafe);
Thread t1 = new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < 500; i++)
set.add(seq.getNext());
}
}, "T1");
t1.start();
Thread t2 = new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < 500; i++)
set.add(seq.getNext());
}
}, "T2");
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(set.size());
}
public int getNext() {
return i.incrementAndGet();
}
}
Related
I'm well aware that this might be considered a duplicate, however I ran through many answers considering my problem here I can't come up with a solution.
I synchronized my runnable with an object shared by multiple threads and explicitly synchronized the method I am using inside, but the outcome of the program is always 3000.
I tried locking the Counter class but it won't change a thing.
Could anyone explain me why none of my actions work in this particular example?
public static void zad3() {
var counter = new Counter();
var toRun = new Runnable() {
#Override
public void run() {
synchronized (counter) {
for (var i = 0; i < 1000; i++) {
counter.add(1);
}
}
}
};
var t1 = new Thread(toRun);
var t2 = new Thread(toRun);
var t3 = new Thread(toRun);
t1.start();
t2.start();
t3.start();
try {
t1.join();
t2.join();
t3.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("counter = " + counter.getCount());
}
public class Counter {
protected long count_ = 0;
public synchronized void add(long value) {
count_ += value;
}
public long getCount() {
return count_;
}
}
edit:
As suggested the problem was in the loop being constantly ran a 1000 times by each of the threads.
My solution:
var toRun = new Runnable() {
#Override
public void run() {
synchronized (counter) {
for (var i = counter.getCount(); i < 1000; i++) {
counter.add(1);
}
}
}
};
Well you have synchronized the complete for loop around the "counter" variable which means that each thread will run tthe block once. 3 X 1000 = 3000
this block will be executed once per thread
for (var i = 0; i < 1000; i++) {
counter.add(1);
}
UPDATE: judging from your comments that you want interrupt on 1000 example code can be:
t1.start();
t2.start();
t3.start();
while(counter.getValue()<1000) {
Thread.sleep(20)
}
Annother suggestion:
public class Incremetor extends Runnable {
Counter counter;
public Incremetor(Counter counter) {
this.counter = counter;
}
public void run() {
counter.increment();
}
}
ExecutorService executorService = Executors.newFixedThreadPool(8); // this mean 8 threads in total to do your runnables.
for (int i=0;i<1000;++i) {
executorService.submit(new Incrementor(counter));
}
So the problem is that you let each thread attempt 1000 increments, so you'll need something like this instead:
while (counter.getCount() < 1000) {
counter.add(1);
}
The solution you have provided may give you the correct result, but you're actually only incrementing the counter from 1 thread. When you make a synchronized block with synchronized(object) { }, all threads will attempt to get the lock for this block, but only one will. That means in your solution, that the first thread which gets the lock, will do all 1000 increments. When the thread releases the lock and lets the others get it, the work is already done. A solution that actually distributes the increments amongst the 3 threads, should therefore not synchronize the entire for-loop.
If you run the while-loop I suggested, you will get a lot closer to 1000, but it may actually be more than 1000. Remember to run your program 10 times or set up a test-function which runs it 100 times and reports back. The problem, is that from the point of reading counter.getCount(), the value may already have changed by another thread. To reliably always get 1000, you could ensure exclusive rights to both reading and writing to the counter:
while (true) {
synchronized (counter) {
if (counter.getCount() < 1000) {
counter.add(1);
} else {
break;
}
}
}
Notice that incrementing one variable like this, is slow. You're only doing 1000, but try with one billion. In fact, the 3-threaded version takes (on my PC) 1m17s, whereas a simple sequential loop takes ~1.2 seconds. You can solve this by splitting the workload amongst the threads and letting them work on a local counter with exclusive rights and then finally add the results.
public class TestThread2 {
static int count = 0;
public static void main(String[] args) {
Thread t = new Thread(new Runnable(){
public void run()
{
for (int i=1; i<=100000; i++) {
count++;
}
}
});
Thread t1 = new Thread(new Runnable(){
public void run()
{
for (int i=1; i<=100000; i++) {
count++;
}
}
});
t.start();
t1.start();
try{
t.join();
t1.join();
}
catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(count);
}
}
The above code prints various values of count such as 131938, 127518 etc. But I think it should always print 20000 as after join() is called, main thread cannot move to next statement until current thread dies. I know I'm missing a basic concept here, but I'm not able to figure it out so please help.
i++ isn't atomic. It's effectively:
int j = i;
i = j + 1;
If two threads are trying to do this at the same time, the reads and writes from different threads could interleave, meaning that the value isn't strictly incrementing in each thread.
Additionally, there is no guarantee that the increased value from one thread is visible to the other thread.
Instead of using int, use AtomicInteger, and addAndGet. AtomicInteger guarantees both the atomicity of the incrementation and the visibility of the value between threads.
static AtomicInteger count = new AtomicInteger();
// In the thread:
count.incrementAndGet();
Note that something very similar to your example is described in the Oracle Java Tutorial.
You are not synchronizing the variables. Instead of static int count, use an AtomicInteger.
Yes main thread blocks on join(). But the main thread does not write to the variable count, so it does not matter what main thread is doing. You have 2 threads, t and t1, which read and write the same variable count without any synchronization, and indeed it causes unstable results.
There is one ArrayList with 1 million element and we are using two threads to read from this ArrayList. The first thread will read first half of the list and second thread will read the second half of list and I am using two threads to achieve this, but I don't see any difference in performance between using one thread and two threads.
I have written below program to achieve this, but I am not sure If this is the right way to implement and achieve this.
Can someone check if my code is correct or how I can fix the multithreading?
import java.util.ArrayList;
import java.util.List;
public class ThreadTask {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
List<Integer> list = new ArrayList<>();
for(int i = 0; i <=1000000; i++){
list.add(i);
}
Thread t1 = new Thread(new PrintList(list));
Thread t2 = new Thread(new PrintList(list));
t1.setName("thread1");
t2.setName("thread2");
long starttime = System.currentTimeMillis();
System.out.println(starttime);
t1.start();
t2.start();
t1.join();
t2.join();
long endtime = System.currentTimeMillis();
System.out.println(endtime);
System.out.println("Total time "+(endtime - starttime));
}
}
class PrintList implements Runnable{
private List list = new ArrayList();
public PrintList(List list){
this.list = list;
}
#Override
public void run() {
if(Thread.currentThread().getName() != null && Thread.currentThread().getName().equalsIgnoreCase("thread1")){
for(int i = 0; i< list.size()/2;i++){
// System.out.println("Thread 1 "+list.get(i));
}
}else if(Thread.currentThread().getName() != null && Thread.currentThread().getName().equalsIgnoreCase("thread2")){
for(int i = list.size()/2; i<list.size(); i++){
//System.out.println("Thread 2 "+list.get(i));
}
}
}
}
Also, If someone can help me on how can we implement it to make it generic to use more then to thread.
System.out.println is synchronized internally (in order that you don't get mixing between the messages printed by multiple threads), so only one thread is actually printing at once.
Basically, it behaves like a single thread.
Even if in reality System.out is synchronized, still you dont want to have manually initialized threads reading from your ArrayList. Plus I doubt that your end goal is the System.out. You should use a higher abstraction. Such abstraction can easily be present either through Java8 Stream API either by ExecutorServices.
Here is one example of paralelism with Java 8 api.
Arraylist toprint;
toPrint.parallelstream().forEach(DoSometing);
This will work in parallel threads.
If you use ExecutorService You can slice your Arraylist and pass each slice to a Callable to perform the work for you in a separate thread.
class Task implements Callable {
List sublist;
public Task(List sublist) {
this.sublist = sublist;
}
public void call() {
// do something
}
}
ArrayList listToSlice;
List<List> slicedList;
ExecutorService executor = Executors.newFixedThreadPool(2);
for (List sublist:slicedList) {
Future<Integer> future = executor.submit(new Task(sublist));
......
.......s on
}
I've read through the API documentation of the java.util.concurrent package, but have obviously misunderstood something. The overview says
A small toolkit of classes that support lock-free thread-safe
programming on single variables.
However, a small test application shows that the AtomicInteger class does not provide thread-safety, at least when it is shared across threads (I accept that the getAndSet / increment methods themselves are at least atomic)
Test:
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicIntTest
{
public static void main(String[] args) throws InterruptedException
{
AtomicInteger atomicInt = new AtomicInteger(0);
WorkerThread w1 = new WorkerThread(atomicInt);
WorkerThread w2 = new WorkerThread(atomicInt);
w1.start();
w2.start();
w2.join(); // <-- As pointed out by StuartLC and BarrySW19, this should be w1.join(). This typo allows the program to produce variable results because it does not correctly wait for *both* threads to finish before outputting a result.
w2.join();
System.out.println("Final value: " + atomicInt.get());
}
public static class WorkerThread extends Thread
{
private AtomicInteger atomicInt = null;
private Random random = new Random();
public WorkerThread(AtomicInteger atomicInt)
{
this.atomicInt = atomicInt;
}
#Override
public void run()
{
for (int i = 0; i < 500; i++)
{
this.atomicInt.incrementAndGet();
try
{
Thread.sleep(this.random.nextInt(50));
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
}
}
When I run this class, I consistently get results ranging from around 950 to 1000, when I would expect to always see exactly 1000.
Can you explain why do I not get consistent results when two threads access this shared AtomicInteger variable? Have I misunderstood the thread-safety guarantee?
Looks like a simple cut&paste error - you are joining to thread "w2" twice and never to "w1". At present, you would expect the thread "w1" to still be running half the time when you print the 'final' value.
I can't Seem to get a final counter value Of 20000. What is wrong with this code?
public class Synchronize2 {
public static void main(String[] args) {
Threading t1 = new Threading();
Threading t2 = new Threading();
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Threading.counter);
}
}
class Threading extends Thread {
static int counter;
public synchronized void incrementer() {
counter++;
}
public void run() {
for (int i=0; i<10000; i++) {
incrementer();
}
}
}
Your synchronized incrementer method will lock on the object itself. But you have 2 different objects, each locking on themselves, so the method isn't thread safe; both threads can still access incrementer at the same time.
Additionally, the post-increment operation isn't thread safe because it's not atomic; there is a read operation and an increment operation, and a thread can be interrupted in the middle of the two operations. This non-thread-safe code presents a race condition, where thread one reads the value, thread two reads the value, then thread one increments and thread two increments, yet only the last increment "wins" and one increment is lost. This shows up when the ending value is less than 20000.
Make the method static too, so that because it's synchronized, it will lock on the class object of the class, which is proper synchronization here.
public static synchronized void incrementer() {
You synchronize on two different Objects. Your incrementer is a short form of this:
public void incrementer() {
synchronized (this) {
counter++;
}
}
But the two instances of "this" are not the same Object. Thus, you do not synchronize at all. Try it this way:
private static Object sync = new Object();
public void incrementer() {
synchronized (sync) {
counter++;
}
}
You should also make the variable counter volatile. It is not strictly neccessary here, because you use it only in synchronized blocks. But in real code you might read it outside such a block, and then you will get problems. Non volatile variables can be read from a local thread cache, instead from the memory.