private static void loop( Supplier<CompletionStage<Boolean>> body) {
CompletionStage<Boolean> result = body.get();
Log.i(TAG,"after get");
result.whenComplete((r, e) -> {
if (r) {
Log.i(TAG,"call loop ");
loop( body);
} else {
Log.i(TAG,"exit loop");
}
});
}
int cnt = 0;
void test() {
CompletableFuture<Void> supervisor = new CompletableFuture<>();
loop(() -> {
Log.i(TAG,"cnt="+cnt);
if(cnt ++ < 40000)
return CompletableFuture.completedFuture(true);
else {
return CompletableFuture.completedFuture(false);
}
});
Log.i(TAG,"leave");
}
Output:
I/MainActivity: cnt=0
I/MainActivity: after get
I/MainActivity: call loop
I/MainActivity: cnt=1
I/MainActivity: after get
I/MainActivity: call loop
...
I/MainActivity: cnt=3073
I/MainActivity: after get
I/MainActivity: call loop
I/MainActivity: cnt=3074
I/MainActivity: after get
I/MainActivity: call loop
I/MainActivity: cnt=3075
I/MainActivity: after get
I/MainActivity: leave
Expect the loop will end after 40000 times, but it only run around 300~4000 times then loop ends.
Related
public class ConTest {
#Test
void name2() {
final MyCounter myCounter = new MyCounter();
final Thread t1 = new Thread(() ->
myCounter.increment()
);
final Thread t2 = new Thread(() ->
myCounter.increment()
);
t1.start();
t2.start();
System.out.println(myCounter.count);
}
#Test
void name3() {
final MyCounter myCounter = new MyCounter();
final ExecutorService service = Executors.newFixedThreadPool(2);
for (int i = 0; i < 2; i++) {
service.execute(() -> {
myCounter.increment();
});
}
System.out.println(myCounter.count);
}
static class MyCounter {
private AtomicLong count = new AtomicLong();
public void increment() {
count.incrementAndGet();
}
}
}
AtomicLong is safe when multi thread.
That is, in the example above, it was executed with 2 threads, so the result should be 2 no matter how many times it is executed.
However, after trying both tests several times, the result is sometimes 1. Why is this happening?
You aren't waiting for any of the background threads or tasks to end before you print the value of the counter. To wait on the tasks to exit, you'll need to add this for threads:
t1.join();
t2.join();
Add this for the service, which prevents new tasks being added and waits a sensible period for them to end:
service.shutdown();
boolean done = awaitTermination(pickSuitablyLongPeriod, TimeUnit.MILLISECONDS);
Once you have ensured the background tasks are completed, the correct result should be printed when you run:
System.out.println(myCounter.count);
This is because the threads are still processing when you call the System.out.println. In this case you would need to block the main thread before you print out the counter.
in the example of the Executor you can just await the termination:
final ExecutorService service = Executors.newFixedThreadPool(2);
final MyCounter myCounter = new MyCounter();
for (int i = 0; i < 100; i++) {
service.submit(myCounter::increment);
}
service.shutdown();
while (!service.awaitTermination(100, TimeUnit.MILLISECONDS)) {
System.out.println("waiting");
}
System.out.println(myCounter.count);
you should avoid to block in productive code, have a look at the Publish/Subscribe design pattern
dont forget to use shutdown() with Executors
see the comments here :
// Here you start the 2 threads
for (int i = 0; i < 2; i++) {
service.execute(() -> {
myCounter.increment();
});
}
// we are not sure here that your 2 threads terminate their tasks or not !!
// the print will be executed by the Main Thread and maybe before the 2 threads terminate their
// job ,
// maybe just one terminate , maybe no one from your 2 threads increment the count .
System.out.println(myCounter.count);
You can use Future class , instead of execute you can use submit() , the retrun type will be of Type Futre<?> (accept void ) , after that with the Future object returned the method get() will block the execution until the result returned from the service :
Example method name3() : will return always 2
void name3() {
final MyCounter myCounter = new MyCounter();
final ExecutorService service = Executors.newFixedThreadPool(2);
Future<?> f = null;
for (int i = 0; i < 2; i++) {
f =service.submit(() -> {
myCounter.increment();
});
try {
f.get();
} catch (InterruptedException | ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(myCounter.count);
service.shutdown();
}
In addition to the above answers, you could add some prints to better understand what is happening.
In summary. You need to wait for the threads to finish executing before expecting the results, so it is not an issue of AtomicLong.
I modified the code, added some prints, and here are results from an execution.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import org.junit.jupiter.api.Test;
public class ConTest {
#Test
void name2() {
final MyCounter myCounter = new MyCounter();
final Thread t1 = new Thread(() -> {
myCounter.increment();
System.out.println("Counter increment t1 completed and the value is " + myCounter.getCount());
});
final Thread t2 = new Thread(() -> {
myCounter.increment();
System.out.println("Counter increment t2 completed and the value is " + myCounter.getCount());
});
t1.start();
t2.start();
System.out.println(myCounter.count.get());
}
#Test
void name3() {
final MyCounter myCounter = new MyCounter();
final ExecutorService service = Executors.newFixedThreadPool(2);
for (int i = 0; i < 2; i++) {
service.execute(() -> {
myCounter.increment();
System.out.println("incrementing for count and the value is " + myCounter.getCount());
});
}
System.out.println(myCounter.count.get());
}
class MyCounter {
private AtomicLong count = new AtomicLong();
public void increment() {
count.incrementAndGet();
}
public long getCount(){
return count.get();
}
}
}
Results (name2)
1
Counter increment t1 completed and the value is 1
Counter increment t2 completed and the value is 2
Results (name3)
incrementing for count and the value is 1
1
incrementing for count and the value is 2
You could also use a debugger to have a better understanding.
I have a simple program for two threads to print, incremental numbers, alternately.
So,
first thread prints : 1
Second thread prints : 2
first thread prints : 3... and so on
I am able to use 'Thread' class to do this. But I want to see how to use Executor class to do this.
With the following code .... executor class does NOT seem to work. Any pointers ??
Code :
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LocksPackagePractice {
private int i = 0;
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
Runnable r = () -> {
for(int x = 0; x < 5; x++){
printValue();
}
printValue();
};
public static void main(String[] args) {
new LocksPackagePractice().trigger();
}
void trigger(){
ExecutorService service = Executors.newFixedThreadPool(2);
service.execute(r);
}
void printValue(){
lock.lock();
try {
i++;
System.out.println(Thread.currentThread().getName() + " and value is = " + i);
condition.signal();
condition.await();
} catch(InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
Made some changes in your program. Run it and check if it solves the confusion.
public class LocksPackagePractice {
private int i = 0;
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
Runnable r = () -> {
printValue();
};
public static void main(String[] args) {
new LocksPackagePractice().trigger();
}
void trigger() {
ExecutorService service = Executors.newFixedThreadPool(2);
service.submit(r);
for (int i = 0; i < 5; i++) {
service.execute(r);
}
}
void printValue() {
lock.lock();
try {
i++;
System.out.println(Thread.currentThread().getName() + " and value is = " + i);
condition.signal();
condition.await();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
This will give you following output
pool-1-thread-1 and value is = 1
pool-1-thread-2 and value is = 2
pool-1-thread-1 and value is = 3
pool-1-thread-2 and value is = 4
pool-1-thread-1 and value is = 5
pool-1-thread-2 and value is = 6
I'm not sure, but do you need input to be ordered ? Because you use blocking operations (locks) and it is not good in case of performance.
This code :
private AtomicInteger number = new AtomicInteger(0);
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
ForTestApplication testApplication = new ForTestApplication();
for (int i = 0; i < 100; i++) {
executor.execute(testApplication::print);
}
}
public void print () {
System.out.println(Thread.currentThread().getName() + " : " + number.incrementAndGet());
}
uses AtomicInteger instead of simple int value and lock operations. But order of output may be like this :
pool-1-thread-1 : 1
pool-1-thread-2 : 2
pool-1-thread-1 : 3
pool-1-thread-1 : 4
pool-1-thread-2 : 5
pool-1-thread-2 : 7
pool-1-thread-1 : 6
pool-1-thread-2 : 8
pool-1-thread-1 : 9
pool-1-thread-2 : 10
It you need order in your output then need to think how to deal with it.
I just started learning "multithreading" in JAVA and it seams I don't understand how keyword "synchronized" works.
I had four examples and they're very alike (in my opinion), and I don't understand why I get every time different results.
public class BufferThread1 {
static int counter = 0;
static StringBuffer s = new StringBuffer();
public static void main(String args[]) throws InterruptedException {
new Thread() {
public void run() {
synchronized (s) {
while (BufferThread1.counter++ < 3) {
s.append("A");
System.out.print("> " + counter + " ");
System.out.println(s);
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
Logger.getLogger(BufferThread1.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
}.start();
Thread.sleep(100);
while (BufferThread1.counter++ < 6) {
System.out.print("< " + counter + " ");
s.append("B");
System.out.println(s);
}
}
}
Result:
run:
> 1 A
< 2 > 3 AA
AAB
< 5 AABB
< 6 AABBB
public class BufferThread2 {
static int counter = 0;
static StringBuilder s = new StringBuilder();
public static void main(String args[]) throws InterruptedException {
new Thread() {
public void run() {
synchronized (s) {
while (BufferThread2.counter++ < 3) {
s.append("A");
System.out.print("> " + counter + " ");
System.out.println(s);
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
Logger.getLogger(BufferThread2.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
}.start();
Thread.sleep(100);
while (BufferThread2.counter++ < 6) {
System.out.print("< " + counter + " ");
s.append("B");
System.out.println(s);
}
}
}
Result:
run:
> 1 A
< 2 AB
< 3 ABB
< 4 ABBB
< 5 ABBBB
< 6 ABBBBB
public class BufferThread3 {
static int counter = 0;
static StringBuffer s = new StringBuffer();
public static void main(String args[]) throws InterruptedException {
new Thread() {
public void run() {
synchronized (s) {
while (BufferThread3.counter++ < 3) {
s.append("A");
System.out.print("> " + counter + " ");
System.out.println(s);
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
Logger.getLogger(BufferThread3.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
}.start();
Thread.sleep(100);
synchronized (s) {
while (BufferThread3.counter++ < 6) {
System.out.print("< " + counter + " ");
s.append("B");
System.out.println(s);
}
}}
}
Result:
run:
> 1 A
> 2 AA
> 3 AAA
< 5 AAAB
< 6 AAABB
Of course, I skipped
import java.util.logging.Level;
import java.util.logging.Logger;
I just don't realise how these examples work and synchronized here !
I do hope that someone help me.
Your < and > label which thread is running here.
> 1 A
Your background thread is running only and prints this line as expected.
< 2
The main thread prints the counter 2 but cannot acquire the lock on s so it blocks.
> 3 AA
The background thread increments the counter again and prints 3 and a second A. On the next iteration it exits and counter == 4 As the thread exits, it releases the lock.
AAB
The main thread can now acquire the lock and append("B")
< 5 AABB
The main thread increments the counter to 5 and adds another B
StringBuffer is a pet hate of mine which was replaced more thna ten years ago by StringBuidler. It is almost impossible to implement a useful thread safe class using it and when people have tried, it has meant the class wasn't really thread safe. Note: SimpleDateFormat uses StringBuffer and it is not thread safe.
Let's try a simpler example that gets at what synchronized does without such an overly complicated class.
Consider the following Runnable task:
public class Task implements Runnable {
private final int id;
public Task(int id) {
this.id = id;
}
public void run() {
for(int i = 0; i < 5; i++) {
System.out.println("Task " + id + " prints " + i);
}
}
}
Then let's try running it with this main method:
public static void main(String[] args) {
Thread t1 = new Thread(new Task(1));
Thread t2 = new Thread(new Task(2));
t1.start();
t2.start();
}
The output could look something like this:
Task 1 prints 0
Task 1 prints 1
Task 1 prints 2
Task 1 prints 3
Task 1 prints 4
Task 2 prints 0
Task 2 prints 1
Task 2 prints 2
Task 2 prints 3
Task 2 prints 4
But it could also look like this:
Task 1 prints 0
Task 2 prints 0
Task 2 prints 1
Task 1 prints 1
Task 1 prints 2
Task 1 prints 3
Task 1 prints 4
Task 2 prints 2
Task 2 prints 3
Task 2 prints 4
Task 2 prints 4
The truth is, you have no guarantees about the order in which the two Tasks execute commands (with respect to each other. You still do know that each task will print 0...4 in order). The fact that t1.start() comes before t2.start() means nothing.
The synchronized command allows for some control over which thread executes when. Essentially, the command synchronized(obj) {....} means that at most one thread is allowed to execute the commands in the block (within the {...}) at a time. This is know as mutual exclusion.
A nice way to think about it is as a locked room with a single key hanging outside on the wall. In order to get into the room, you have to take the key off the wall, unlock the door, go into the room, and lock it from the inside. Once you are done doing whatever you are doing in the room, you unlock the door from the inside, go outside, lock the door from the outside, and hang the key up. It is clear that while you are in the room no one else can join you, as the door is locked and you currently hold the only key to get in.
To illustrate, consider the following improved task class:
public class SynchronizedTask implements Runnable {
private final Object lock;
private final int id;
public Task(int id, Object lock) {
this.id = id;
this.lock = lock;
}
public void run() {
synchronized(lock) {
for(int i = 0; i < 5; i++) {
System.out.println("Task " + id + " prints " + i);
}
}
}
}
And run it with the following modified main method:
public static void main(String[] args) {
Object lock = new Object();
Thread t1 = new Thread(new Task(1, lock));
Thread t2 = new Thread(new Task(2, lock));
t1.start();
t2.start();
}
We still don't know whether t1 or t2 will enter the synchronized block first. However, once has entered, the other must wait for it to finish. Thus, there are exactly two possible outputs of this code. Either t1 gets in first:
Task 1 prints 0
Task 1 prints 1
Task 1 prints 2
Task 1 prints 3
Task 1 prints 4
Task 2 prints 0
Task 2 prints 1
Task 2 prints 2
Task 2 prints 3
Task 2 prints 4
Or t2 gets in first:
Task 2 prints 0
Task 2 prints 1
Task 2 prints 2
Task 2 prints 3
Task 2 prints 4
Task 1 prints 0
Task 1 prints 1
Task 1 prints 2
Task 1 prints 3
Task 1 prints 4
It is important to note that this behavior only worked as desired because we used the same lock object for both Tasks. If we had run the following code instead:
public static void main(String[] args) {
Thread t1 = new Thread(new Task(1, new Object()));
Thread t2 = new Thread(new Task(2, new Object()));
t1.start();
t2.start();
}
We would have identical behavior to the original un-synchronized code. This is because we now have a room with two (or really, infinite if we replicate our thread initialization) keys hanging outside. Thus while t1 is inside the synchronized block, t2 can just use its own key to get in, defeating the whole purpose.
First example shown by Mr. Lawrey.
In the second example the "Background" thread only gets to do one print of and since StringBuilder is used this time instead of StringBuffer the main thread will not block while trying to print "s", hence only 1 A.
In the third example the main thread is blocked until the background thread terminates because you start the background thread before the main thread's loop. Thus the background thread will get 3 loops done and hence the 3 A's.
Though I suspect these are artificial examples for learning purposes it should still be noted that sleeping inside a synchronized block is NOT a good idea as this will not release the lock.
I am strange with something in for loop. If i call setCurrentId(1) then generateid will return 0(return statement execute inside for loop ). Again if i call with setCurrentId(2) it returns 0(return statement execute outside for loop ) which is not supposed to.
I have a profile ArrayList which has been created before with id 1,2,3,4. So i am now checking a random id with these id.But in the for loop it only execute 1st time.
public void setCurrentId(int id) {
Log.d("status scd :", "scI a " + id);
this.current_id = GenerateId(id);
Log.d("status scd :", "scI b " + this.current_id);
}
public int GenerateId(int profile_id) {
if (AppController.getInstance().getProfile() != null) {
Log.d("status scd :", "GI ");
for (int i = 0; i < AppController.getInstance().getProfile().size() && AppController.getInstance().getProfile().get(i).getId() == profile_id; i++) {
return i;
}
}
return 0;
}
Log result is :
status scd :: scI a 1
status scd :: GI
status scd :: scI b 0
status scd :: scI a 2
status scd :: GI
status scd :: scI b 0
so,i debug and found that 2nd condition is not executing after 1st call of setCurrentId().
When i place the 2nd condition inside if then it works fine. But don't know why this is happening.So, i am curious to figure it out.
here is corrected code :
public void setCurrentId(int id) {
Log.d("status scd :", "scI a " + id);
this.current_id = GenerateId(id);
Log.d("status scd :", "scI b " + this.current_id);
}
public int GenerateId(int profile_id) {
if (AppController.getInstance().getProfile() != null) {
Log.d("status scd :", "GI ");
for (int i = 0; i < AppController.getInstance().getProfile().size(); i++) {
if (AppController.getInstance().getProfile().get(i).getId() == profile_id) {
return i;
}
}
}
return 0;
}
And the log result :
status scd :: scI a 1
status scd :: GI
status scd :: scI b 0
status scd :: scI a 2
status scd :: GI
status scd :: scI b 1
Your condition in the For loop says AND (&&). The first loop looks for the condition to be true to iterate and since that being false it omits the loop.
Iteration is possible only with True functionality for any multiple conditions in for loop. In your second code snippet loop condition is true until i< the size of Profile List and hence loop being triggered.
#skyman statement Condition in for loop means 'do when true' so loop body is skipped. this is correct.
It is good practice to see the second code snippet in real time. Reason being is exception handling. Also, i see in your code snippet conventions are not being used just for your reference.Java Conventions
AppController.getInstance().getProfile().get(i).getId() == profile_id is probably false for first profile item so you do not step into loop and 0 is returned.
Condition in for loop means 'do when true' so loop body is skipped.
So I'm having a bit of trouble with this exercise. I solved one of the problems by synchronizing the arraylist in each thread, but there's still something wrong. The arraylist "data" is filled up with numbers from 0 to 9999. However, data.get(i); seems to be returning 0 at every single index, and i can't for the life of me figure out why. Here's the code:
private static int LIST_TRAVERSE_LIMIT = 10000; // size of problem
private boolean problem_3_failed = false; // set to true if failed
private List<Integer> data = new ArrayList<Integer>(); // data shared between threads, traversed and modified
private int negative_hits = 0; // counter for how many modifications are found during traversal
private void test_parallel_iteration() {
for(int i=0; i<LIST_TRAVERSE_LIMIT; i++) data.add(i);
// Define threads and run them
Thread t1 = new Thread(() -> { // modify the list in just a few places
synchronized(data){
for(int i=0; i<LIST_TRAVERSE_LIMIT; i++)
if(data.get(i)%(LIST_TRAVERSE_LIMIT/3)==0) data.add(0, -data.get(i));
}
});
Thread t2 = new Thread(() -> { // iterate the list
try {
synchronized(data){
for(int i: data)
if(i<0) {
System.out.println("Found negative number: "+i);
negative_hits++;
}
}
} catch(ConcurrentModificationException exn) {
System.out.println("Problem 3, thread 2 failed: concurrent modification");
problem_3_failed = true;
}
});
finish(t1,t2);
// What happened?
System.out.println("#Negative hits: "+negative_hits);
if(problem_3_failed) System.out.println("Problem 3 failed");
else System.out.println("Problem 3 succeeded");
}
private void finish(Thread t1, Thread t2) {
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
throw new Error("Internal error: interrupted!");
}
}
Output:
#Negative hits: 0
Problem 3 succeeded
You're programming yourself into an infinite loop. Here's how:
Your list is a series of numbers from 0 - 10000, with i being the index into that list for the current element:
0 1 2 3 4 5 ...
^
i
When the condition data.get(i)%(LIST_TRAVERSE_LIMIT/3)==0 executes on the first element of the list (zero), the check succeeds. Then, you add an element at the beginning of the list, which is negative zero (still zero), and continue to the next element.
Now your List looks like this, but note what is at i:
0 0 1 2 3 4 ....
^
i
So, it looks like every element is zero, because it is!