Simply put, i'm trying to see the difference when using sychronized keyword over just running a function over threads without locks at all.
In this code:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.IntStream;
public class mainClass {
static int count=0;
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
Runnable r =new Runnable() {
public synchronized void run() {
count = count + 1;
}
};
IntStream.range(0, 10000)
.forEach(i -> executor.submit(r::run));
executor.shutdown();
System.out.println(count); // 10000
}
}
It doesn't work as i predicated it to work, it returns 10000 in like 40% of the runs. Why is that? Where is the problem?
I thought that the function run is being run by only 1 Thread at a time, so there shouldn't be problem, but clearly i'm wrong.
ExecutorService#shutdown does not wait for tasks to complete. You should use awaitTermination for that.
See the documentation for ExecutorService#shutdown.
IntStream.range(0, 10000)
.forEach(i -> executor.submit(r::run));
executor.shutdown();
executor.awaitTermination(1, TimeUnit.MINUTE); // <!-- HERE
Related
I have two concurrent threads (producer and consumer), and two queues (pending and execution).
This is a sample flow for producer:
"1" - If not duplicate (does not exist in any of queues), push task T1
"3" - If not duplicate (does not exist in any of queues), push task T1
And this is a sample flow for consumer:
"2" - Poll data from "pending" queue
"4" - If found something, push it into "execution" queue and run it in a separate thread.
Notice the numbering above:
If between steps 2 and 4, step 3 happens, it can insert a duplicate because the data is still in-memory and is not pushed into "execution" queue yet.
How can I prevent this? I can not put a lock on both queues because then the "consumer" thread will always keep the lock (it is an always running thread polling for data).
P.S.
This is how my consumer looks like:
while ( true ) {
var nextTask = pending.poll(100, MILLISECOND); //STEP 2
if ( nextTask != null ) {
executeQueue.add(nextTask); //STEP 4
executeInParallel(nextTask);
}
}
This might not be a direct answer to your question. But if you are looking for a solution to queue tasks to process them with a number of threads you should have a look at the Executors from Java.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class JobQueue {
public static void main(String[] args) {
ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
executorService.submit(() -> {
// do someting
return "result";
});
}
}
Update: check queue:
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
public class JobQueue {
public static void main(String[] args) {
ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
Runnable task = () -> {
// do someting
};
BlockingQueue<Runnable> queue = executorService.getQueue();
if(!queue.contains(task)) {
executorService.submit(task);
}
}
}
You can synchromize on an Object uning wait() and notify()
import java.util.ArrayDeque;
import java.util.HashSet;
import java.util.Queue;
import java.util.Set;
public class JobQueue {
private static final Object syncMon = new Object();
private static final Queue<Object> pending = new ArrayDeque<>();
private static final Set<Object> executing = new HashSet<>();
public void produce(Object o) {
synchronized (syncMon) {
if(pending.contains(o) || executing.contains(o))
return;
pending.add(o);
syncMon.notifyAll();
}
}
public Object consume() throws InterruptedException {
synchronized (syncMon) {
if(pending.isEmpty())
syncMon.wait();
Object task = pending.poll();
if(task != null) {
executing.add(task);
}
return task;
}
}
public void complete(Object task) {
synchronized (syncMon) {
executing.remove(task);
}
}
}
The syncMon object is not necesarry. You could also use wait() and notify() on the Queue directly.
like pending.notifyAll();
To explain this a litte: If you invoke wait() in a synchronized block the lock is released. So the producer can enter the synchronized while the consumer is waiting. If you call notify() or notifyAll() the waiting thread wakes up and takes the lock back, once the producer has exited the synchronized block.
Update 1: add execution set.
I want to do some timing tasks using ScheduledExecutorService, but time intervals are changeable. I try to reschedule a task before it finished:
import java.io.IOException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Test {
public static ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
public static int interval = 1;
public static void main(String[] args) throws IOException {
Runnable runnable = new Runnable() {
#Override
public void run() {
System.out.println(System.currentTimeMillis() / 1000);
interval += 1;
scheduledExecutorService.schedule(this, interval, TimeUnit.SECONDS);
}
};
scheduledExecutorService.schedule(runnable, interval, TimeUnit.SECONDS);
}
}
But, I never found anyone do timing tasks using ScheduledExecutorService like this, I wonder whether it's safe.
As long as you use the method schedule that executes the task only once, there is nothing wrong with this approach, it will only re-schedule at each iteration the same task with a different delay. For the scheduler it will be seen as a new task scheduled at each iteration, nothing more.
Can we write Threadpool executor service inside an executor service ?
Can anyone suggest how to run parallel tasks inside parallel tasks ?
Suppose there are 10 tasks which need to run in parallel and inside each task I have to run 100 parallel tasks. Any suggestions please
ExecutorService executor1 = Executors.newFixedThreadPool(8);
for (int i = 0; i < 8; i++) {
ExecutorService executor2 = Executors.newFixedThreadPool(115);
for (int j = 0; j < 115; j++) {
Runnable worker = new UpdatecheckerTest(Region.getRegion(Regions.US_EAST_1),"");
executor2.execute(worker);
}
}
executor1.shutdown();
Is this the correct approach ?
This approach will work, but I think the right solution depends on a few other things that you are not mentioning.
Simple Case
if the problem you are trying to solve is very simple, short, not a very big part of your overall system and performance or stability is not much of a concern. i wouldn't even bother with using a Thread pool at all and just use parallel streams
your code could look something like this:
IntStream.range(0,8).().forEach(i -> {
IntStream.range(0,115).parallel().forEach(j -> {
new UpdatecheckerTest(Region.getRegion(Regions.US_EAST_1),"").run();
});
});
Main part of the overall system
If the problem you are trying to solve is really a major part of your system, when i look at what you are describing i actually see a large task which is representing what is happening inside the outer loop (the i loop) and a small tasks which is representing what is happening inside the inner loop (the j loop). If those tasks take up a main role in your system you might want to put those tasks in their own classes to make them more readable, reusable and easier to change later on.
your code could look something like that:
SmallTask.java
import java.text.MessageFormat;
public class SmallTask implements Runnable {
private String identifier;
public SmallTask (String identifier) {
this.identifier = identifier;
}
#Override
public void run() {
System.out.println(String.format(MessageFormat.format("Executing SmallTask with id: {0}", identifier)));
// what ever happens in new UpdatecheckerTest(Region.getRegion(Regions.US_EAST_1),"").run()
}
}
LargeTask.java
import java.text.MessageFormat;
import java.util.stream.IntStream;
public class LargeTask implements Runnable {
private String identifier;
public LargeTask (String identifier) {
this.identifier = identifier;
}
#Override
public void run() {
System.out.println(String.format(MessageFormat.format("Executing LargeTask with id: {0}", identifier)));
IntStream.range(0, 115).parallel().forEach(j -> {
new SmallTask(identifier + "-" + String.valueOf(j)).run();
});
}
}
Main.java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
IntStream.range(0,8).parallel().forEach(i -> {
new LargeTask(String.valueOf(i)).run();
});
}
}
i would even go a step further and say that the large task or what initiates it could be an event in an event driven architecture you could organize your system to have different kinds of events all of which could be executed asynchronously.
Performance and stability matters
If this code runs very frequently in you system then i would consider using a thread poll which allows you to control how many threads are being used and if the threads allocated to run LargeTask are the same as those allocated to run SmallTask or not.
then your code could look something like this:
SmallTask.java
import java.text.MessageFormat;
public class SmallTask implements Runnable {
private String identifier;
public SmallTask (String identifier) {
this.identifier = identifier;
}
#Override
public void run() {
System.out.println(String.format(MessageFormat.format("Executing SmallTask with id: {0}", identifier)));
// what ever happens in new UpdatecheckerTest(Region.getRegion(Regions.US_EAST_1),"").run()
}
}
LargeTask.java
import java.text.MessageFormat;
import java.util.stream.IntStream;
public class LargeTask implements Runnable {
private String identifier;
public LargeTask (String identifier) {
this.identifier = identifier;
}
#Override
public void run() {
System.out.println(String.format(MessageFormat.format("Executing LargeTask with id: {0}", identifier)));
IntStream.range(0, 115).forEach(j -> {
TasksExecutor.getSmallTaskExecutor().execute(new SmallTask(identifier + "-" + String.valueOf(j)));
});
}
}
TasksExecutor.java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TasksExecutor {
private static ExecutorService largeTasksExecutor = Executors.newFixedThreadPool(8);
private static ExecutorService smallTaskExecutor = Executors.newFixedThreadPool(115);
public static ExecutorService getLargeTaskExecutor () {
return largeTasksExecutor;
}
public static ExecutorService getSmallTaskExecutor () {
return smallTaskExecutor;
}
}
Main.java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
IntStream.range(0,8).forEach(i -> {
TasksExecutor.getLargeTaskExecutor().execute(new LargeTask(String.valueOf(i)));
});
}
}
Don't forget to add functionality to close the thread pool if needed.
and maybe add some sort of dependency injection between each task and the specific thread pool that you want to manage it it will give you better flexibility later on
If you want to take it a step further you could instead use a Messaging Framework where you could use different queues to manage all the tasks that need to take place. like ZeroMQ and Kafka
The code below checks the usage of ExecutorCompletionService from Java Concurrency framework (the IDE being used is Netbeans).
But the program doesn't terminate. Why?
Code:
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.Executors;
public class TestFuture {
public static void main(String... args) throws InterruptedException, ExecutionException {
Executor ex = Executors.newCachedThreadPool();
CompletionService<Long> cs = new ExecutorCompletionService<Long>(ex);
cs.submit(new Worker());
cs.submit(new Worker());
cs.submit(new Worker());
for (int i = 0; i < 3; i++) {
long l = cs.take().get();
//utilize the result
System.out.println(l);
}
}
}
class Worker implements Callable {
#Override
public Long call() throws Exception {
//do some task and return back
return System.currentTimeMillis();
}
}
Threads in thread pool will keep running when main is finished. That's why JVM won't shut down. You need to either use daemon-threads, or shutdown the pool explicitly.
Here's an example:
ExecutorService ex = Executors.newCachedThreadPool();
// do all your submission work here
ex.shutdown();
The output of the following simple code is a little odd to me.
it miss out some of the numbers between 0 and 100 to print on the console.
could anyone explain why it omit to print? i am completely new to concurrency programming.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.junit.Test;
public class SimpleTest {
#Test
public void testSimple() throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(10);
for(int i = 0; i <= 100; i++) {
executorService.execute(new SimpleRunnable(i));
}
executorService.shutdown();
}
}
class SimpleRunnable implements Runnable {
int i;
public SimpleRunnable(int i) {
this.i = i;
}
public void run() {
synchronized(System.out) {
System.out.println(i);
}
}
}
You should wait for the executor service to finish after calling shutdown
executorService.shutdown();
executor.awaitTermination(30, TimeUnit.SECONDS); // Wait for the tasks to finish.
// and flush!
System.out.flush();
I suspect the threads created are daemon threads, which do not prevent a JVM shutdown. Since the threads are kicked off and forgotten, after your call to shutdown, the method returns and then the JVM exits because there is nothing else to do. Unfinished work never gets done.
As Elliot pointed out, use the awaitTermination method:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html#awaitTermination(long, java.util.concurrent.TimeUnit)