OK so I have a GUI Java application that permits the user to select and launch between 5-500 software devices each represented by a Thread. The Threads continuously update the GUI with information.
The user can select threads and pause, resume or kill them.
All the information on threads and thread pools, interrupts, Future.... I just got lost and wanted to set fire to the internet =)
What I need is some clear guidance on the standard way forward for this. I have below the outline of my thread class here.
Is this a good template to start with ? If not please edit.
package ACsimForm;
import java.util.Random;
import javax.swing.SwingUtilities;
public class Squeak implements Runnable {
private String name = "";
private javax.swing.JTextArea ScroolPage;
Squeak (String name, javax.swing.JTextArea MW )
{
this.value = true;
this.name = name;
this.ScroolPage = MW;
}
Random r = new Random();
int num = r.nextInt(10-1) + 1;
#Override
public void run ()
{
updateGUI("Thread "+name+" Loaded and Running");
while(true)
{
updateGUI("New Data");
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
updateGUI("Thread "+name+" Exiting!");
//return exits the method killing the thread
return;
}
}
}
//this is the new way to communicate back to the GUI
private void updateGUI(final String foo) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ScroolPage.append(foo+"\r\n");
}
});
}
}
What is the best way to keep tack of up 500 threads in a way that permits you to kill or pause/resume them from the GUI?
Many Thanks.
I think your Runnable is almost there. Abandon the idea of a magic Boolean flag - this is plagued with issues (read up on volatile). Use the interrupt itself as a signal. This is why it's there!
Here is a simple example of a system with an arbitrary number of Threads:
private static final class Printer implements Runnable {
private final String printMe;
public Printer(String printMe) {
this.printMe = printMe;
}
#Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + "says: " + printMe);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException ex) {
return;
}
}
}
}
public static void main(String[] args) throws Exception {
final ExecutorService executorService = Executors.newCachedThreadPool();
final Map<Integer, Future<?>> futures = new HashMap<>();
for (int i = 0; i < 10; ++i) {
futures.put(i, executorService.submit(new Printer("Printer" + i)));
}
final Scanner scanner = new Scanner(System.in);
while (true) {
final String input = scanner.nextLine();
if ("EXIT".equalsIgnoreCase(input)) {
break;
}
final Integer threadToStop;
try {
threadToStop = Integer.parseInt(input);
} catch (NumberFormatException ex) {
System.out.println("Not a number");
continue;
}
final Future<?> f = futures.remove(threadToStop);
if (f == null) {
System.out.println("Not a valid thread");
continue;
}
f.cancel(true);
}
executorService.shutdownNow();
}
We use an ExecutorService to manage the Threads - you should never use Threads directly, this is again plagued with land mines.
The ExecutorService is asked to run an arbitrary number of tasks - you can see how to add tasks in the for loop.
Then ExecutorService returns a Future for each task added - these are handles to the tasks. They allow us to check if they are still going/done or have encountered an error.
We Map the Futures to task names and than allow the user to selectively kill tasks from input.
You cannot "pause" and "resume" a Thread (well you can, but you are better off not worrying about that). You simply cancel a task when you want it paused and then reissue it to restart it. The good thing is that the ExecutorService will recycle the Thread that the task was running on so you won't loose performance.
If you are issuing commands to the Map of Futures from multiple threads you would need a ConcurrentHashMap.
A common pitfall is assuming that your application will exit cleanly with the ExecutorService running. This is not the case. The ExecutorService spawns non-daemon threads and so the application cannot exit until they are all done. You have two options; the first is a bit hacky - just give the ExecutorService your own ThreadFactory and make the Threads daemon, the second is to shutdown the ExecutorService when you are done with it as I have in the example.
This is not a complete answer but a few tips to get things done.
You should use an ExecutorService for your threads, and .submit() them. In order to register them and have them available, say by name, create a Map<String, Future<?>>.
Some pseudo code, could be improved:
#GuardedBy("this") // see JSR 305
final Map<String, Future<?>> allSqueaks
= new HashMap<String, Future<?>>();
final ExecutorService service
= Executors.newCachedThreadPool();
// Registering:
public synchronized void registerSqueak(final Squeak squeak)
{
allSqueaks.put(squeak.getName(), service.submit(squeak));
}
// Cancelling:
public synchronized void cancelSqueakByName(final String name)
{
// Note: deal with non existing name if it can happen
final Future<?> victim = allSqueaks.remove(name);
victim.cancel(true);
}
Related
I have a need to run some threads concurrently, but need to force each process to run in a new Thread (this is due to some ThreadLocal bleed that I don't have full control over). To do so, I have been using the SimpleAsyncTaskExecutor. However, the issue with this is that it doesn't maintain a queue that allows new tasks to be submitted once it's reached the concurrency limit. What I really need to do is have functionality like the SimpleAsyncTaskExecutor but where tasks can still be submitted even after the concurrency limit has been reached - I just want those tasks to wait in the queue until another slot frees up. This is what I have right now:
SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();
taskExecutor.setConcurrencyLimit(maxThreads);
return taskExecutor;
Is there some out-of-the-box solution for this, or do I need to write something custom?
To ensure you need to execute every task in a new Thread, You are basically against use of any ThreadPool (ThreadLocal behavior in a ThreadPool is something you need to get rid of, sooner or later).
To overcome this, you can simply produce something like this,
class ThreadPerTaskExecutor implements Executor {
public void execute(Runnable r) {
Thread t = new Thread(r);
t.start();
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
which executes the Runnable always in a new Thread.
Coming to a crude implementation, We can do something like
final Executor executor = new ThreadPerTaskExecutor();
final ExecutorService service = Executors.newFixedThreadPool(3);
for (int i = 0; i < 100; i++) {
service.submit(new Runnable() {
public void run() {
try {
System.out.println("Executed inside Thread pool with concurrency level 3"
+ Thread.currentThread().toString());
executor.execute(new Runnable() {
public void run() {
try {
Thread.sleep(3000); //Some expensive operations here.
System.out.println(
"Executed inside new Thread always" + Thread.currentThread().toString());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
This can be improved with lambdas as well after Java 8. Hope this sheds the basic idea.
Is there some out-of-the-box solution for this, or do I need to write something custom?
I think there is no out-of-the-box solution for this, and you need to write your own code for this.
You can extend the SimpleAsyncTaskExecutor for simpler/quicker implementation. Example:
public class SimpleAsyncQueueTaskExecutor extends SimpleAsyncTaskExecutor {
private Queue<Runnable> queue = new ConcurrentLinkedQueue<Runnable>();
private AtomicInteger concurrencyValue = new AtomicInteger(0);
private void checkAndExecuteFromQueue() {
int count = concurrencyValue.get();
if (isThrottleActive() && !queue.isEmpty() &&
(count < getConcurrencyLimit())) {
Runnable task = queue.poll();
concurrencyValue.incrementAndGet();
doExecute(new ConcurrencyThrottlingRunnable(task));
}
}
private void afterExecute(Runnable task) {
queue.remove(task);
concurrencyValue.decrementAndGet();
// Check and execute other tasks
checkAndExecuteFromQueue();
}
#Override
public void execute(Runnable task, long startTimeout) {
Assert.notNull(task, "Runnable must not be null");
if (isThrottleActive() && startTimeout > TIMEOUT_IMMEDIATE) {
queue.offer(task);
checkAndExecuteFromQueue();
} else {
doExecute(task);
}
}
private class ConcurrencyThrottlingRunnable implements Runnable {
private final Runnable target;
public ConcurrencyThrottlingRunnable(Runnable target) {
this.target = target;
}
#Override
public void run() {
try {
this.target.run();
}
finally {
afterExecute(this.target);
}
}
}
This example code just add a queue, and override the execute method.
Hope this help.
I have got a class that records eyetracking data asynchronously. There are methods to start and stop the recording process. The data is collected in a collection and the collection can only be accessed if the recording thread has finished its work. It basically encapsulates all the threading and synchronizing so the user of my library doesn't have to do it.
The heavily shortened code (generics and error handling omitted):
public class Recorder {
private Collection accumulatorCollection;
private Thread recordingThread;
private class RecordingRunnable implements Runnable {
...
public void run() {
while(!Thread.currentThread().isInterrupted()) {
// fetch data and collect it in the accumulator
synchronized(acc) { acc.add(Eyetracker.getData()) }
}
}
}
public void start() {
accumulatorCollection = new Collection();
recordingThread = new Thread(new RecordingRunnable(accumulatorCollection));
recordingThread.start();
}
public void stop() {
recordingThread.interrupt();
}
public void getData() {
try {
recordingThread.join(2000);
if(recordingThread.isAlive()) { throw Exception(); }
}
catch(InterruptedException e) { ... }
synchronized(accumulatorCollection) { return accumulatorCollection; }
}
}
The usage is quite simple:
recorder.start();
...
recorder.stop();
Collection data = recorder.getData();
My problem with the whole thing is how to test it. Currently i am doing it like this:
recorder.start();
Thread.sleep(50);
recorder.stop();
Collection data = recorder.getData();
assert(stuff);
This works, but it is non-deterministic and slows down the test suite quite a bit (i marked these tests as integration tests, so they have to be run separately to circumvent this problem).
Is there a better way?
There is a better way using a CountDownLatch.
The non-deterministic part of the test stems from two variables in time you do not account for:
creating and starting a thread takes time and the thread may not have started executing the runnable when Thread.start() returns (the runnable will get executed, but it may be a bit later).
the stop/interrupt will break the while-loop in the Runnable but not immediately, it may be a bit later.
This is where a CountDownLatch comes in: it gives you precise information about where another thread is in execution. E.g. let the first thread wait on the latch, while the second "counts down" the latch as last statement within a runnable and now the first thread knows that the runnable finished. The CountDownLatch also acts as a synchronizer: whatever the second thread was writing to memory, can now be read by the first thread.
Instead of using an interrupt, you can also use a volatile boolean. Any thread reading the volatile variable is guaranteed to see the last value set by any other thread.
A CountDownLatch can also be given a timeout which is useful for tests that can hang: if you have to wait to long you can abort the whole test (e.g. shutdown executors, interrupt threads) and throw an AssertionError. In the code below I re-used the timeout to wait for a certain amount of data to collect instead of 'sleeping'.
As an optimization, use an Executor (ThreadPool) instead of creating and starting threads. The latter is relative expensive, using an Executor can really make a difference.
Below the updated code, I made it runnable as an application (main method). (edit 28/02/17: check maxCollect > 0 in while-loop)
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
public class Recorder {
private final ExecutorService executor;
private Thread recordingThread;
private volatile boolean stopRecording;
private CountDownLatch finishedRecording;
private Collection<Object> eyeData;
private int maxCollect;
private final AtomicBoolean started = new AtomicBoolean();
private final AtomicBoolean stopped = new AtomicBoolean();
public Recorder() {
this(null);
}
public Recorder(ExecutorService executor) {
this.executor = executor;
}
public Recorder maxCollect(int max) { maxCollect = max; return this; }
private class RecordingRunnable implements Runnable {
#Override public void run() {
try {
int collected = 0;
while (!stopRecording) {
eyeData.add(EyeTracker.getData());
if (maxCollect > 0 && ++collected >= maxCollect) {
stopRecording = true;
}
}
} finally {
finishedRecording.countDown();
}
}
}
public Recorder start() {
if (!started.compareAndSet(false, true)) {
throw new IllegalStateException("already started");
}
stopRecording = false;
finishedRecording = new CountDownLatch(1);
eyeData = new ArrayList<Object>();
// the RecordingRunnable created below will see the values assigned above ('happens before relationship')
if (executor == null) {
recordingThread = new Thread(new RecordingRunnable());
recordingThread.start();
} else {
executor.execute(new RecordingRunnable());
}
return this;
}
public Collection<Object> getData(long timeout, TimeUnit tunit) {
if (started.get() == false) {
throw new IllegalStateException("start first");
}
if (!stopped.compareAndSet(false, true)) {
throw new IllegalStateException("data already fetched");
}
if (maxCollect <= 0) {
stopRecording = true;
}
boolean recordingStopped = false;
try {
// this establishes a 'happens before relationship'
// all updates to eyeData are now visible in this thread.
recordingStopped = finishedRecording.await(timeout, tunit);
} catch(InterruptedException e) {
throw new RuntimeException("interrupted", e);
} finally {
stopRecording = true;
}
// if recording did not stop, do not return the eyeData (could stil be modified by recording-runnable).
if (!recordingStopped) {
throw new RuntimeException("recording");
}
// only when everything is OK this recorder instance can be re-used
started.set(false);
stopped.set(false);
return eyeData;
}
public static class EyeTracker {
public static Object getData() {
try { Thread.sleep(1); } catch (Exception ignored) {}
return new Object();
}
}
public static void main(String[] args) {
System.out.println("Starting.");
ExecutorService exe = Executors.newSingleThreadExecutor();
try {
Recorder r = new Recorder(exe).maxCollect(50).start();
int dsize = r.getData(2000, TimeUnit.MILLISECONDS).size();
System.out.println("Collected " + dsize);
r.maxCollect(100).start();
dsize = r.getData(2000, TimeUnit.MILLISECONDS).size();
System.out.println("Collected " + dsize);
r.maxCollect(0).start();
Thread.sleep(100);
dsize = r.getData(2000, TimeUnit.MILLISECONDS).size();
System.out.println("Collected " + dsize);
} catch (Exception e) {
e.printStackTrace();
} finally {
exe.shutdownNow();
System.out.println("Done.");
}
}
}
Happy coding :)
I am writing a GUI game, and I want to wait for the game to finish, before returning the winner. However, since my Game manager class is separate from the class used to implement the game logic and detect a win, I want to know how I can make the game manager wait until the other class notifies it of a win, and then proceed to do other stuff. I have not really worked much with multithreading before, so I'm hoping someone could explain how I might achieve this.
Here is some relevant code from the GameManager class' main that I've tried:
...
Game game = new Game(mode);
String winner = game.getWinner();
...
And from the Game class:
public Game(Game.Mode mode){
this.board = new Board(7);
window = new BoardFrame(7, 7, mode, board); //Graphical interface
window.setVisible(true);
}
public String getWinner(){
synchronized(board.WINNER){
try {
board.WINNER.wait();
} catch (InterruptedException e) {}
}
return board.WINNER;
}
And the Board class:
public boolean update(int num){
if (isValidMove(CurrentPlayer, num)){
buttonClients.get(positions.get(CurrentPlayer)).clear();
positions.put(CurrentPlayer, num);
board[num] = 1;
buttonClients.get(num).performCallback(CurrentPlayer);
if ((WINNER = isGameFinished())!=""){
//Disable all further inputs
for (int i = 0; i<board.length; i++){
board[i] = 1;
}
synchronized (WINNER) {
WINNER.notify();
}
}
CurrentPlayer = (CurrentPlayer==PLAYER1)?PLAYER2:PLAYER1;
return true;
}
return false;
}
EDIT: So I have found the cause of the screen display issue, which is that all my code for the GameManager was in an EventQueue.invokeLater() block. I have taken it out of that block for now, and the screen is displaying properly now. However, when I play until the end, and the synchronized(WINNER) block is finally run, it seems like nothing happens? In other words, the game continues waiting on WINNER.
When I'm waiting on a thread, my favorite is using a CountDownLatch and Maybe using a Callable<V> and submitting it to a thread executor which returns a Future<V> which blocks until the thread is done.
public class Example {
ExecutorService executorService = Executors.newCachedThreadPool();
public void init(){
CountDownLatch latch = new CountDownLatch(1);
Future<Boolean> submit = executorService.submit(new Thread3());
executorService.execute(new Thread1(latch, submit));
executorService.execute(new Thread2(latch));
}
public class Thread1 implements Runnable{
private CountDownLatch latch;
private Future<Boolean> thread3;
public Thread1(CountDownLatch latch, Future<Boolean> thread3) {
this.latch = latch;
this.thread3 = thread3;
}
#Override
public void run() {
int i = 0;
try {
thread3.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
while (i < 50){
LockSupport.parkNanos(1000);
i++;
}
latch.countDown();
}
}
public class Thread2 implements Runnable{
private CountDownLatch latch;
public Thread2(CountDownLatch latch) {
this.latch = latch;
}
#Override
public void run() {
try {
latch.await();
System.out.println("We can continue");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Thread3 implements Callable<Boolean>{
#Override
public Boolean call() throws Exception {
int i = 0;
while (i < 50){
LockSupport.parkNanos(1000);
i++;
}
return true;
}
}
}
Good Resource:
http://tutorials.jenkov.com/java-concurrency/index.html
There's a couple of ways you could do this, but by far the neatest will be to use the observer pattern to create an event listener. The idea behind this pattern is to allow code to register an action to be performed when an event occurs, while isolating the event handler from the action it's going to invoke. Note that this solution doesn't require any multithreading.
If you really do want your GUI and game logic running on separate threads, seems like you're trying to implement the locking approach described here. There's a couple of things to watch out for:
The JVM can give you a waiting thread an InterruptedException at any time, for any reason. You should always check the condition that caused you to wait before you proceed.
Any time you're accessing state shared across threads, you need to make sure you are using synchronized and volatile appropriately.
Where you lock on WINNER, bear in mind this field can change. If Board is locked on WINNER and changes its value, a new thread entering Game would be free to obtain its lock before the Board block completes, because they're locking on different objects.
I am trying to manipulate this program to print ":---)))))" repeatedly.
I understand that a semaphore is a way of controlling threads, and acquire essentially acquires a permit (reads) and release returns a permit back to the semaphore. (writes)
I've tried manipulating the number of permits when initializing the semaphores, but I am not understanding how to sync them together because I can't figure out how exactly the semaphores operate with how they acquire and release.
I am looking for a helpful explanation that pertains to Java in the context of only using semaphores, acquire and release and how they work together to properly put the threads "in sync"
import java.lang.Thread;
import java.util.concurrent.*;
public class ThreadSync {
private static boolean runFlag = true;
private static Semaphore canPrintC = new Semaphore(1);
private static Semaphore canPrintD = new Semaphore(0);
private static Semaphore canPrintP = new Semaphore(0);
public static void main(String [] args) {
// Create and start each runnable
Runnable task1 = new TaskPrintC();
Runnable task2 = new TaskPrintD();
Runnable task3 = new TaskPrintP();
Thread thread1 = new Thread(task1);
Thread thread2 = new Thread(task2);
Thread thread3 = new Thread(task3);
thread1.start();
thread2.start();
thread3.start();
// Let them run for 500 ms
try {
Thread.sleep(500);
}
catch (InterruptedException e) {
e.printStackTrace();
}
runFlag = false;
thread3.interrupt();
thread2.interrupt();
thread1.interrupt();
}
public static class TaskPrintC implements Runnable {
public void run() {
while (runFlag) {
try {
canPrintC.acquire();
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.printf("%s", ":");
canPrintD.release();
}
}
}
public static class TaskPrintD implements Runnable {
public void run() {
while (runFlag) {
try {
canPrintD.acquire();
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.printf("%s", "-");
canPrintP.release();
}
}
}
public static class TaskPrintP implements Runnable {
public void run() {
while (runFlag) {
try {
canPrintP.acquire();
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.printf("%s", ")");
canPrintC.release();
}
}
}
}
Threads execute tasks and semaphores can help you to let tasks (or runnable objects) know each other's state (e.g. task A waits for input from task B and task B can signal task A that input is available). The difference between a task and a thread is important.
To stress this point, I have taken your example and made one runnable class that performs the task of printing a character a number of times (configured via variables in the constructor). To mimic the serialized behavior (tasks run after each other), the runnable is also aware of the next runnable that should perform the print task.
To complete the example I also ensured that the thread that is executing the main-method is aware of when the tasks have completed, so that the program stops at the proper time. A CountDownLatch is used in this case (a CountDownLatch is a very simple variation of a Semaphore).
The example below might be a bit hard to understand, but it shows some good practices (re-use code, using a stop-flag instead of interrupt, use an executor to run tasks, cleanup and stop tasks in case of error). It also shows how Semaphores can orchestrate the execution of tasks.
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class ChainedSemaphoreTasks {
// amount of times chained tasks are executed.
static int MAX_CHAINED_LOOPS = 3;
// helper to let main-thread know when chained loops have been executed.
final static CountDownLatch MAX_LOOPS_REACHED = new CountDownLatch(1);
public static void main(String[] args) {
String printChars = ":-)";
int[] repeatChars = { 1, 3, 5};
List<ChainedTask> tasks = buildTasks(printChars, repeatChars);
ExecutorService executor = Executors.newCachedThreadPool();
for (ChainedTask task : tasks) {
executor.execute(task);
}
try {
// Trigger first task to start running.
tasks.get(0).triggerPrintTask();
// wait for loop to complete, but not too long.
if (!MAX_LOOPS_REACHED.await(5000L, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("Chained tasks loop did not complete within timeout.");
}
long waitStart = System.currentTimeMillis();
executor.shutdown();
if (executor.awaitTermination(1000L, TimeUnit.MILLISECONDS)) {
System.out.println("All tasks stopped within " + (System.currentTimeMillis() - waitStart) + " ms.");
} else {
throw new RuntimeException("Not all chained tasks stopped within timeout.");
}
} catch (Exception e) {
e.printStackTrace();
// cleanup
try {
tasks.get(0).stop();
} catch (Exception e2) {
e2.printStackTrace();
}
executor.shutdownNow();
}
}
static List<ChainedTask> buildTasks(String printChars, int[] repeatChars) {
List<ChainedTask> tasks = new ArrayList<ChainedTask>();
int maxTasks = printChars.length();
if (maxTasks != repeatChars.length) {
throw new IllegalArgumentException("Amount of repeats per pritn character must match amount of characters.");
}
for (int i = 0; i < maxTasks; i++) {
ChainedTask task = new ChainedTask(printChars.charAt(i), repeatChars[i]);
tasks.add(task);
if (i > 0) {
tasks.get(i - 1).setNextTask(task);
}
}
// make last task trigger first task - creates an endless loop.
tasks.get(maxTasks - 1).setNextTask(tasks.get(0));
tasks.get(maxTasks - 1).setLastTask(true);
return tasks;
}
static AtomicInteger chainedLoopsCount = new AtomicInteger();
static class ChainedTask implements Runnable {
// Semaphore to trigger execution
Semaphore performTask = new Semaphore(0);
// If stop is true, task must finish.
// stop must be volatile to ensure updated value is always visible.
volatile boolean stop = false;
// The last task is responsible for stopping execution
boolean lastTask;
// The next task to run after this task.
ChainedTask nextTask;
char printChar;
int repeatAmount;
ChainedTask(char printChar, int repeatAmount) {
this.printChar = printChar;
this.repeatAmount = repeatAmount;
System.out.println("Created " + printChar + " / " + repeatAmount);
}
void triggerPrintTask() {
performTask.release(repeatAmount);
}
void stop() {
// first indicate to stop
stop = true;
// then release a permit to pickup the stop sign.
performTask.release();
// also stop next task, unless this is the last task
if (!isLastTask()) {
getNextTask().stop();
}
}
#Override
public void run() {
try {
while (!stop) {
runTask();
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Stopped " + printChar + " / " + repeatAmount);
}
void runTask() throws Exception {
// wait for our turn
performTask.acquire();
// must check 'stop' after getting permit, see the stop-method:
// first stop is set to true and then a permit is released.
if (stop) {
return;
}
// print text for loop-amount
do {
System.out.print(printChar);
} while (performTask.tryAcquire());
if (isLastTask()) {
System.out.println();
// check if we should stop
if (chainedLoopsCount.incrementAndGet() >= MAX_CHAINED_LOOPS) {
// since this is the last task, the next task is the first task.
// stopping the first task will call the stop-method on all tasks, including this one.
getNextTask().stop();
// signal main-thread we are done.
MAX_LOOPS_REACHED.countDown();
}
// Sleep for a long time to test what happens when last task hangs.
// Should trigger the "cleanup" code in the main method.
// Thread.sleep(10000);
}
// trigger next chained task to run
// this has no effect if next chained task was stopped
getNextTask().triggerPrintTask();
}
void setNextTask(ChainedTask nextTask) {
this.nextTask = nextTask;
}
ChainedTask getNextTask() {
return nextTask;
}
void setLastTask(boolean lastTask) {
this.lastTask = lastTask;
}
boolean isLastTask() {
return lastTask;
}
}
}
Semaphore – to solve Producer/Consumer problem
A high level explanation of semaphore.
A semaphore contains a count indicating whether a resource is locked or available. Semaphore is a signaling mechanism (“I am done, you can carry on.”). The resource itself may not be thread safe.
Producer
semObject.Post(); // Send the signal
Increase the semaphore count by 1. If a thread is waiting on the
specified semaphore, it is awakened.[1]
Consumer
semObject.Wait(); // Wait for the signal
When the semaphore count is zero, the thread calling this function
will wait for the semaphore. When the semaphore count is nonzero, the
count will be decremented by 1 and the thread calling this function
will continue.[1]
Reference
[1] Massa, Anthony J., Embedded software development with eCos, Pearson Education, Inc., 2002
I have a class which processes something. I'm trying to run a number of instances of this class in parallel.
However, I'm not sure if in TaskManager.startAll(), when I call r.go(), whether this would cause r to start running in its own thread, or within the main thread?
The total execution time that I'm getting seems to be very high, and despite my attempts at optimizing, nothing seems to be having any effect. Also, if I run a profiler on my project in Netbeans, it shows all the threads as sleeping. So I'd like to know if I'm doing something wrong?
This is the structure of the class:
public class TaskRunner implements Runnable {
private boolean isRunning = false;
public void run() {
while(true) {
while (! running) {
try {
Thread.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
process();
}
}
public void go() {
isRunning = true;
}
public void stop() {
isRunning = false;
}
private void process() {
//Do some number crunching and processing here
}
}
Here's how these are being run / managed:
public class TaskManager {
private ArrayList<TaskRunner> runners = new ArrayList<>();
public TaskManager() {
for (int i = 0; i < 10; i++) {
TaskRunner r = new TaskRunner();
new Thread(r).start();
runners.add(r);
}
}
public void startAll() {
for (TaskRunner r : runners) {
r.go();
}
}
}
Indeed, you are not "doing it right." If you want to create a multi-threaded Java application, the place to start is with the java.util.concurrent package.
It appears from your code that you want to run ten tasks in parallel. I assume that after "number crunching and processing," you'll want to aggregate the results and do something with them in the main thread. For this, the invokeAll() method of ExecutorService works well.
First, implement Callable to do the work you show in your process() method.
final class YourTask implements Callable<YourResults> {
private final YourInput input;
YourTask(YourInput input) {
this.input = input;
}
#Override
public YourResults call()
throws Exception
{
/* Do some number crunching and processing here. */
return new YourResults(...);
}
}
Then create your tasks and run them. This would take the place of your main() method:
Collection<Callable<YourResults>> tasks = new List<>(inputs.size());
for (YourInput i : inputs)
tasks.add(new YourTask(i));
ExecutorService workers = Executors.newFixedThreadPool(10);
/* The next call blocks while the worker threads complete all tasks. */
List<Future<YourResult>> results = workers.invokeAll(tasks);
workers.shutdown();
for (Future<YourResult> f : results) {
YourResult r = f.get();
/* Do whatever it is you do with the results. */
...
}
However, I'm not sure if in TaskManager.startAll(), when I call r.go(), whether this would cause r to start running in its own thread, or within the main thread?
So my first comment is that you should make isRunning be volatile since it is being shared between threads. If the threads are not starting when it goes to true (or seem to be delayed in starting) then I suspect that's your problem. volatile provides memory synchronization between the threads so the thread that calls go() and makes a change to isRunning will be seen immediately by the thread waiting for the change.
Instead of spinning like this, I would use wait/notify:
// this synchronizes on the instance of `TaskRunner`
synchronized (this) {
// always do your wait in a while loop to protect against spurious wakeups
while (!isRunning && !Thread.currentThread().isInterrupted()) {
try {
// wait until the notify is called on this object
this.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
Then in the go() method you should do the following. stop() would be similar.
public void go() {
synchronized (this) {
isRunning = true;
this.notifyAll();
}
}
Notice that you should handle thread interrupts carefully. Test for isInterrupted() in the while running loop and re-interrupt a thread when InterruptedException is thrown is always a good pattern.
The total execution time that I'm getting seems to be very high, and despite my attempts at optimizing, nothing seems to be having any effect. Also, if I run a profiler on my project in Netbeans, it shows all the threads as sleeping.
So although the threads are mostly sleeping, they are still each looping 1000 times a second because of your Thread.sleep(1). If you increased the time sleeping (after making isRunning be volatile) they would loop less but the right mechanism is to use the wait/notify to signal the thread.
Awful solution, terrible. first I highly recommend you start reading some tutorial like [this]
Second, if threads should wait for a signal to go for some job, so why just don't you wait them!!!!!, something like this
import java.util.ArrayList;
public class TaskManager
{
//////////////////////
public volatile static Signal wait=new Signal();
//////////////////////
private ArrayList<TaskRunner> runners = new ArrayList<>();
public TaskManager()
{
for (int i = 0; i < 10; i++)
{
TaskRunner r = new TaskRunner();
new Thread(r).start();
runners.add(r);
}
try {
Thread.sleep(1000);
startAll();
Thread.sleep(1000);
pauseAll();
Thread.sleep(1000);
startAll();
Thread.sleep(1000);
haltAll();System.out.println("DONE!");
}catch(Exception ex){}
}
public void startAll()
{
synchronized(wait){
wait.setRun(true);;
wait.notifyAll();
}
}
public void pauseAll(){
wait.setRun(false);
}
public void haltAll(){
for(TaskRunner tx:runners){tx.halt();}
}
public static void main(String[] args) {
new TaskManager();
}
}
class TaskRunner implements Runnable
{
private Thread thisThread;
private volatile boolean run=true;
public void run()
{
thisThread=Thread.currentThread();
while(run){
if(!TaskManager.wait.isRun()){
synchronized(TaskManager.wait)
{
if(!TaskManager.wait.isRun()){
System.out.println("Wait!...");
try
{
TaskManager.wait.wait();
}
catch (Exception e)
{
e.printStackTrace();
break;
}
}
}}
process();
}
}
private double r=Math.random();
private void process(){System.out.println(r);try {
Thread.sleep(10);
} catch (Exception e) {
// TODO: handle exception
}}
public void halt(){run=false;thisThread.interrupt();}
}
class Signal{
private boolean run=false;
public boolean isRun() {
return run;
}
public void setRun(boolean run) {
this.run = run;
}
}
in above sample, all runners works till the Signal run boolean is true, and simple TaskManager class set tit as false for every time it needs to pause the threads. and about the halt, it just set the shutdown(run) flag to false, and also interrupt the thread because of if thread is in wait state.
I hope I could prove your solution is like dream-on story, and also could explained enough about my solution.
have a good parallel application :)