Java Multithreading application issue - java

I have to simulate the activity of a postal office, where an office worker can offer many services like paying bills, send letters etc. I have created a separate application which simulates the incoming clients and store them in the database. The second application has to manage the "clients" from the database and assign to each office worker "clients" that have requested specific tasks. If the office worker is busy then the client should be added in a waiting queue. Each office worker should do the job in a new thread. The problem is that when i run the application only one thread is doing his job. Then the application stops. Anyone has any suggestions on how can i implement this application using multithreading?
Office worker class
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Random;
import ro.csm.database_access.OperationDatabaseAccess;
import ro.csm.database_access.TaskDatabaseAccess;
public class OfficeWorker {
//each office worker has a queue of tasks, a list of supported operations, an office and a thread
private Queue<Task> tasks;
private List<Operation> supportedOperations;
private Thread workingThread;
private Office office;
//constructor
public OfficeWorker(Office office){
this.office = office;
supportedOperations = OperationDatabaseAccess.getAllSupportedOperations(office.getId());
workingThread = new Thread();
workingThread.start();
setTasks(new LinkedList<Task>());
}
//add task to the tasks queue
public void addTask(Task task){
getTasks().add(task);
}
//finish the task
public void work(){
while(true){
Task t = getTasks().poll();
if(t != null){
TaskDatabaseAccess.setTaskCompleted(t.getId());
try {
Thread.sleep(getCompletionTime(t));
workingThread.stop();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//generate a random completion time for each task considering the minimum time and the maximum time allocated for a task
private int getCompletionTime(Task t){
Operation op = OperationDatabaseAccess.getOperationByTaskId(t.getId());
int min = op.getMinTime();
int max = op.getMaxTime();
Random rand = new Random();
return rand.nextInt(max - min + 1) - min;
}
Main application class
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import ro.csm.database_access.OfficeDatabaseAccess;
import ro.csm.database_access.OperationDatabaseAccess;
import ro.csm.database_access.TaskDatabaseAccess;
import ro.csm.models.Office;
import ro.csm.models.OfficeWorker;
import ro.csm.models.Operation;
import ro.csm.models.Task;
public class MainApplication {
//list of available offices
static List<Office> offices = OfficeDatabaseAccess.getOffices();
//list of office workers
static List<OfficeWorker> workers = createOfficeWorker(offices);
public static void main(String[] args) {
while(true){
//get the list of pending tasks
List<Task> tasks = TaskDatabaseAccess.getNotStarted();
for(Task t : tasks){
//for each task set the status in progress
TaskDatabaseAccess.setTaskInProgres(t.getId());
//assign the task to a office worker
assignTaskToOfficeWorker(t);
}
}
}
public static void assignTaskToOfficeWorker(Task t){
//create a list of possible workers
List<OfficeWorker> possibleWorkers = new ArrayList<OfficeWorker>();
//get the supported operations for each office worker
for(OfficeWorker ow : getWorkers()){
List<Operation> supportedOperations = OperationDatabaseAccess.getAllSupportedOperations(ow.getOffice().getId());
//check if the given task is in the list of supported operations
for(Operation op : supportedOperations){
if(op.getId() == t.getIdOperation()){
//if the task can be executed by this office worker then add this worker in the list of possible workers
possibleWorkers.add(ow);
}
}
}
//assign the task to the worker that has the smallest queue tasks
OfficeWorker toBeAssigned = findOWMinTaskInQueue(possibleWorkers);
toBeAssigned.addTask(t);
//update the task with the office number
TaskDatabaseAccess.updateTaskWithOfficeInformation(toBeAssigned.getOffice().getId(), t.getId());
//complete the task
toBeAssigned.work();
}
public static List<OfficeWorker> createOfficeWorker(List<Office> offices){
List<OfficeWorker> workers = new ArrayList<OfficeWorker>();
for(Office office : offices){
OfficeWorker ow = new OfficeWorker(office);
workers.add(ow);
}
return workers;
}
public static OfficeWorker findOWMinTaskInQueue(List<OfficeWorker> workers){
Collections.sort(workers, new Comparator<OfficeWorker>() {
public int compare(final OfficeWorker ow1, final OfficeWorker ow2){
return ((Integer) ow1.getTasks().size()).compareTo((Integer)ow2.getTasks().size());
}
});
return workers.get(0);
}

The problem is that you not doing any multitasking. Your OfficeWorker is just class that creates empty thread and starts it.
Here is basic example:
new Thread(new Runnable() {
public void run() {
//do something
}
}).start();
Please read this docs http://docs.oracle.com/javase/tutorial/essential/concurrency/simple.html to understand more.

Related

Syncrhonization across two queues and threads

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.

Concurrency in Java - Delegating tasks to worker threads, am I doing it right?

So I'm making an emulator for an online game and I can't seem to think of a good way to deal with lots of tasks running simultaneously. Loading everything on a single thread just doesn't work, obviously.
My idea was to have a main thread that delegates tasks to x amount of worker threads. Once the main thread is done queueing tasks, it signals the workers to start firing tasks and halts untill they have finished. My implementation is as follows:
package com.rs2.engine;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.CountDownLatch;
import java.util.ArrayList;
import com.rs2.util.Timer;
public class Engine implements Runnable {
private ScheduledExecutorService scheduledExecutorService;
private ExecutorService executorService;
private int currentTick;
private ArrayList<Task> tasks;
private Timer timer;
public Engine(int workers) {
this.executorService = Executors.newFixedThreadPool(workers);
this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
this.currentTick = 0;
this.tasks = new ArrayList<>(10000);
this.timer = new Timer();
}
public int getCurrentTick() {
return currentTick;
}
public ExecutorService getWorkers() {
return executorService;
}
public void start() {
this.scheduledExecutorService.scheduleAtFixedRate(this, 0, 600, TimeUnit.MILLISECONDS);
}
public void cycle() {
}
public void queueTask(Task task) {
tasks.add(task);
}
public void processQueuedTasks() {
try {
CountDownLatch latch = new CountDownLatch(tasks.size());
for (int i = 0; i < tasks.size(); i++) {
Task t = tasks.get(i);
t.setCountDownLatch(latch);
executorService.submit(t);
}
latch.await();
tasks.clear();
} catch(Exception e) {
e.printStackTrace();
}
}
#Override
public void run() {
timer.reset();
cycle();
currentTick++;
//System.out.println("Cycle time: "+timer.elapsed());
}
}
queueTask() and processQueuedTasks() are only called from the main thread. This Engine is used to deal with any and all tasks that the server needs executing. First it processes networking events (incoming packets), then updating entities and other events. That's why I like to keep it abstract.
Here's the Task class aswell:
package com.rs2.engine;
import java.util.concurrent.CountDownLatch;
public class Task implements Runnable {
private CountDownLatch latch;
public Task() {
}
#Override
public void run() {
execute();
latch.countDown();
}
public void execute() {
}
public void setCountDownLatch(CountDownLatch latch) {
this.latch = latch;
}
}
My questions are as follows:
In the Engine class, is it OK to work with a regular ArrayList in terms of concurrency?
Is there a better way of queueing tasks to the ExecutorService? I feel like it might cause issues if too many tasks are queued to it at the same time.
Are there any engine frameworks I should be looking at before I start reinventing the wheel?
If you are worried that you might be queueing too much tasks in the ExecutorService you can use Semaphore to limit the tasks it can run at a time.
Put it in your processQueuedTasks() method for loop to limit the number of tasks to be run.
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html
Instead of using a Semaphore to throttle the number of tasks run concurrently, you could set the number of threads in the threadpool. You will only get as many tasks running concurrently as you have threads
Executors.newFixedThreadPool(n);
public void queueTask(Task task) {
As this method is public, it can be called from any thread and so the ArrayList would not be thread safe. Think about what would happen if you tried to queue a task during the time they are submitted to the executor. You have 'borrowed' functionality from a thread pool executor and placed it in your code by having the collection for tasks.

java thread sync between multiple objects

I have a multi-thread multi-object system in which I have a manager and multiple workers. I need to synchronize the workers with the manager, like this:
manager does sth, gives the order to the workers, and then let the workers run in parallel, independent of each other. When they finished this round, they must wait for the manager to give them the new task or order. The manager issues the new order only if all the workers have finished their previous job.
I need to implement it using threads to avoid busy-waiting. However the synchronization is confusing.
Any idea?
EDIT: i missed a important part that says new tasks should arrive only when all have finished. Therefore using LinkedBlockingQueue is not the best solution. I recommend using the CyclicBarrier boris-the-spider has recomended.
You can use a LinkedBlockingQueue
Set a fixed capacity.
The manager can put tasks, and the workers can use function take to wait.
As #boristhespider suggested, I used CyclicBarrier for both manager and workers.
After each worker finishes its task, it calls barrier.await(). Then for the manager, I check if barrier.getNumberWaiting()==NumWorkers. If it's true, it updates the tasks of each worker and then calls barrier.await().
Maintain 2 Blocking queues
1. for Task
2. for free worker
Let worker notify manager via a callback, which add them to free worker queue
Inside manager thread you can check for workers available.
quick implementation
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
public class ManagerWorker {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
BlockingQueue<String> taskQueue = new LinkedBlockingQueue<>();
Manager m = new Manager(5, taskQueue);
service.submit(m);
for (int i = 0; i < 5; i++) {
service.submit(new Worker(m, taskQueue));
}
}
}
class Manager implements Runnable {
int workerCount;
BlockingQueue<Worker> workerqueue = new LinkedBlockingQueue<>();
BlockingQueue<String> taskQueue;
public Manager(int workerCount, BlockingQueue<String> taskQueue) {
this.workerCount = workerCount;
this.taskQueue = taskQueue;
}
public void callBackForFreeNotification(Worker worker) {
workerqueue.add(worker);
}
#Override
public void run() {
while (true) {
try {
int i = 0;
while (i < workerCount) {
workerqueue.take();
i++;
}
System.out.println("Manager Worker available");
// add task to task queue here
for (int j = 0; j < workerCount; j++) {
taskQueue.add("task");
}
System.out.println("Manager task added");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Worker implements Runnable {
private Manager manager;
private BlockingQueue<String> taskQueue;
public Worker(Manager manager, BlockingQueue<String> taskqueue) {
this.manager = manager;
this.taskQueue = taskqueue;
}
#Override
public void run() {
while(true){
try {
System.out.println("Worker - i have no work");
manager.callBackForFreeNotification(this);
taskQueue.take();
System.out.println("Worker working");
Thread.sleep(2000);
System.out.println("Worker Done with work");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

Challenging Java Program Using Threads [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
Help figuring out this coding question: At this company their are 3 branches and each branch has 3 computers. This network with has a central router that connects the computers to the proper data storage and printers. All print data and storage retrieval data must pass through the router. This router is a single processor. Make a class Router. Then write a stimulation to test your Router code. Create 9 threads one for each port on the Router and launch them simultaneously. Stimulate the functions with the following calls.
Job(PB,1,D,60000)
Job(PB,3,P,100000)
Job(PB,2,D,75000)
Job(FB,1,P,30000)
Job(FB,2,D,150000)
Job(FB,3,P,89000)
Job(MB,1,P,200000)
Job(MB,2,D,140000)
Job(MB,3,P,1350000)
Where Job(Branch, Computer port, D=Data P=Print, Number of characters)
After all runs are done, have your router software print the following by branch:
The number of data characters processed and cost of processing.
The number of print characters processed and cost of processing.
3 The total of characters processed and total cost of processing.
The charges are computed as follows:
Production Branch; print connection 0.007 cents/char, data connection 0.008 cents/char
Financial Branch; print connection 0.009 cents/char, data connection 0.007 cent/char
Marketing Branch; print connection 0.0095 cents/char, data connection 0.0082
import java.io.;
import java.io.IOException;
import javax.swing.;
import java.util.;
import java.io.File;
import java.io.FileNotFoundException;
import java.lang.IllegalStateException;
import java.util.NoSuchElementException;
import java.lang.;
//import java.lang.Thread;//This allows the threads to be run
import java.util.concurrent.;//This allows the creation of a thread pool that can all be launched by
//one executor Executor
import java.util.concurrent.locks.; //this gives me the ability to lock a function
public class Homework_02 {
public static void main(String[] args) throws Exception {
//Create PrintWriter for separate output
PrintWriter outf1;
outf1=new PrintWriter(new File("Homework_02Out.txt"));
//create thread pool without executor
//Production Branch
Runnable printPB1=new Job("PB",1,'D',60000);
Runnable printPB3=new Job("PB",3,'P',100000);
Runnable printPB2=new Job("PB",2,'D',75000);
//Financial Branch
Runnable printFB1=new Job("FB",1,'P',30000);
Runnable printFB2=new Job("FB",2,'D',150000);
Runnable printFB3=new Job("FB",3,'P',89000);
//Marketing Branch
Runnable printMB1=new Job("MB",1,'P',200000);
Runnable printMB2=new Job("MB",2,'D',140000);
Runnable printMB3=new Job("MB",3,'P',135000);
//Create Threads
Thread thread1=new Thread(printPB1);
Thread thread2=new Thread(printPB2);
Thread thread3=new Thread(printPB3);
Thread thread4=new Thread(printFB1);
Thread thread5=new Thread(printFB2);
Thread thread6=new Thread(printFB3);
Thread thread7=new Thread(printMB1);
Thread thread8=new Thread(printMB2);
Thread thread9=new Thread(printMB3);
/*Prioritize (if needed)
thread1.setPriority(Thread.MAX_PRIORITY);
thread2.setPriority(Thread.MAX_PRIORITY);
thread3.setPriority(Thread.MAX_PRIORITY);
thread4.setPriority(Thread.MAX_PRIORITY);
thread5.setPriority(Thread.MAX_PRIORITY);
thread6.setPriority(Thread.MAX_PRIORITY);
thread7.setPriority(Thread.MAX_PRIORITY);
thread8.setPriority(Thread.MAX_PRIORITY);
thread9.setPriority(Thread.MAX_PRIORITY);
*/
//Now start the threads
thread1.start();
thread2.start();
thread3.start();
thread4.start();
thread5.start();
thread6.start();
thread7.start();
thread8.start();
thread9.start();
//flush(if needed)
outf1.flush();
}
}
class Job implements Runnable{
private String branch;
private int port;
private static char type;
private static double characters;
public Job(String b, int x, char t, double num){
branch=b;
port=x;
type=t;
characters=num;
}
public void run() {
// TODO Auto-generated method stub
}
}
Probably not quite what was asked for as I don't see the need for threads but I've used threads anyway. I've also used Locks to demonstrate how they work, but I have also used Atomics so the locks are probably not necessary.
enum Branch {
Production(0.007, 0.008),
Financial(0.009, 0.007),
Marketing(0.0095, 0.0082);
// PB/FB/MB
final String id = name().charAt(0) + "B";
// Costs.
final double printCost;
final double dataCost;
private Branch(double printCost, double dataCost) {
this.printCost = printCost;
this.dataCost = dataCost;
}
// One lock for each computer at this branch.
Lock[] computers = new Lock[3];
{
for (int i = 0; i < computers.length; i++) {
computers[i] = new ReentrantLock();
}
}
public void lock(int computer) {
computers[computer - 1].lock();
}
public void unlock(int computer) {
computers[computer - 1].unlock();
}
AtomicInteger dataProcessed = new AtomicInteger();
public void data(int amount) {
dataProcessed.addAndGet(amount);
}
AtomicInteger printProcessed = new AtomicInteger();
public void print(int amount) {
printProcessed.addAndGet(amount);
}
public static Branch lookup(String id) {
for (Branch b : Branch.values()) {
if (b.id.equals(id)) {
return b;
}
}
return null;
}
private void printStats() {
System.out.println("Branch " + name()
+ " processed " + dataProcessed
+ " cost=" + (dataProcessed.get() * dataCost)
+ " printed " + printProcessed
+ " cost=" + (printProcessed.get() * printCost)
);
}
}
enum Function {
Data {
#Override
void function(Branch b, int size) {
b.data(size);
}
},
Print {
#Override
void function(Branch b, int size) {
b.print(size);
}
};
// D/P
final String id = "" + name().charAt(0);
public static Function lookup(String id) {
for (Function b : Function.values()) {
if (b.id.equals(id)) {
return b;
}
}
return null;
}
abstract void function(Branch b, int size);
}
class Router {
public void job(String branch, int computer, String function, int size) {
Branch b = Branch.lookup(branch);
// Grab the lock on that computer at that branch.
b.lock(computer);
try {
Function f = Function.lookup(function);
f.function(b, size);
} finally {
b.unlock(computer);
}
}
private void job(Job j) {
job(j.branch, j.computer, j.function, j.data);
}
private void printStats() {
// For all branches:
for (Branch b : Branch.values()) {
b.printStats();
}
}
}
// Just one router.
final Router router = new Router();
class Job implements Runnable {
String branch;
int computer;
String function;
int data;
public Job(String branch, int computer, String function, int data) {
this.branch = branch;
this.computer = computer;
this.function = function;
this.data = data;
}
#Override
public void run() {
router.job(this);
}
}
public void test() throws InterruptedException {
System.out.println("Hello");
Job[] jobs = {
new Job("PB", 1, "D", 60000),
new Job("PB", 3, "P", 100000),
new Job("PB", 2, "D", 75000),
new Job("FB", 1, "P", 30000),
new Job("FB", 2, "D", 150000),
new Job("FB", 3, "P", 89000),
new Job("MB", 1, "P", 200000),
new Job("MB", 2, "D", 140000),
new Job("MB", 3, "P", 1350000)};
Thread[] threads = new Thread[jobs.length];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(jobs[i]);
threads[i].start();
}
for (int i = 0; i < threads.length; i++) {
threads[i].join();
}
router.printStats();
}
prints:
Branch Production processed 135000 cost=1080.0 printed 100000 cost=700.0
Branch Financial processed 150000 cost=1050.0 printed 119000 cost=1071.0
Branch Marketing processed 140000 cost=1148.0 printed 1550000 cost=14725.0
Please note carefully - as a professional developer I post professional level code. Please do not attempt to present this to your teacher as if it was yours. They will know immediately that it is not.
You should use this code to understand the techniques that are available to you.

How to run Parallel tasks inside parallel tasks

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

Categories