Stop the running threads from an array - java

I have an array of threads and I want to start a few of them. The point is that I want to stop the threads with in a for loop.
In the for loop I want to check all threads if they are running or not, and if they are, I want to be asked if I want stop them(dialog box yes/no).
The problem is that the loop doesn't display all the times all three dialog boxes for all those three started thread. Sometime appear 1 dialog box, sometime 3 dialog boxes etc.
So, I do not have the chance to stop all three threads...
public class Main {
public static void main( String[] args )
{
Counter[] arrayOfThreads = new Counter[10];
for( int i = 0; i < arrayOfThreads.length; i++ )
{
arrayOfThreads[i] = new Counter( );
}
arrayOfThreads[3].start( );
arrayOfThreads[5].start( );
arrayOfThreads[2].start( );
for( int i = 0; i < arrayOfThreads.length; i++ )
{
if( arrayOfThreads[i].getState( ) == State.RUNNABLE )
{
int dialogButton = JOptionPane.YES_NO_OPTION;
int dialogResult = JOptionPane.showConfirmDialog( null, "Do you want to stop the theread: " + i, "Warning", dialogButton );
if( dialogResult == JOptionPane.YES_OPTION )
{
arrayOfThreads[i].stopProcessing( );
}
}
}
}
}
class Counter extends Thread
{
volatile boolean processing;
public void run( )
{
int i = 0;
processing = true;
while( processing )
{
System.out.println( " Number: " + i );
i++;
}
System.out.println( "finish" );
}
public void stopProcessing( )
{
processing = false;
}
}
EDIT:
So all what I want is when I press the EXIT button to close the threads and to dispose the frame if all the threads are stoped. I modified the first class to more more clear.
public class Program extends Frame {
public static void main(String[] args) {
Counter[] arrayOfThreads = new Counter[10];
for (int i = 0; i < arrayOfThreads.length; i++) {
arrayOfThreads[i] = new Counter();
}
Program program = new Program(arrayOfThreads);
program.startThreeThreads(1, 4, 5);
}
private Counter[] arrayOfThreads;
private JButton stopThreads;
public Program(Counter[] arrayOfThreads) {
this.arrayOfThreads = arrayOfThreads;
stopThreads = new JButton("STOP THREADS");
closeThreadsWhenExitIsPressed();
setSize(300, 200);
setLayout(new FlowLayout());
add(stopThreads);
setVisible(true);
}
public void closeThreadsWhenExitIsPressed() {
stopThreads.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
stopRunningThreadsMethod();
dispose();
}
});
}
private void startThreeThreads(int first, int second, int third) {
for (int i = 0; i < arrayOfThreads.length; i++) {
if (i == first || i == second || i == third) {
arrayOfThreads[i].start();
continue;
}
}
}
public void stopRunningThreadsMethod() {
for (int i = 0; i < arrayOfThreads.length; i++) {
if (arrayOfThreads[i].isAlive()) {
int dialogButton = JOptionPane.YES_NO_OPTION;
int dialogResult = JOptionPane.showConfirmDialog(null, "Do you want to stop the theread: " + i,
"Warning", dialogButton);
if (dialogResult == JOptionPane.YES_OPTION) {
arrayOfThreads[i].stopProcessing();
}
}
}
}
}

The documentation for getState() is (my emphasis):
Returns the state of this thread. This method is designed for use in
monitoring of the system state, not for synchronization control.
You're trying to use it for synchronization so you're already outside recommendation.
If you look at Thread.State you'll see it isn't always RUNNABLE and I suspect, as is common, System.out is synchronized so although not obvious from your code the thread could be WAITING (on another competing thread to use System.out).
Given all your thread does is hammer output it's probably quite common one or more is waiting. You could even find none show the dialog because as you go round the loop you happen to coincide with that thread waiting!
Check this by reading the state and outputting it!
So first, don't use getState() for synchronization and be aware you don't always know what synchronization is going on 'behind the scenes' in libraries you're using.
The documentation gives leave for the implementer to maybe cut corners in low-level synchronization of getState() and the value may not be 'first class' reliable (synchronized), but regardless don't do things you're told not to even if you don't know why!
The right method is isAlive(). The thread is alive if it has had its start() method called and not yet terminated. Waiting or not, it's alive...
Next problem, is because you set processing=true; in the run() method you could call stopProcessing() before processing has been set true.
There is no guarantee how far (if anywhere) down run() the thread has got when you reach stopProcessing() in the main thread.
I know there's a user interaction (e.g. big delay) but on an overloaded (or single threaded!) machine or a future use case it is possible for processing=true; to be executed after stopProcessing() sets it false. That may lead to 'runaway' processing.
So use volatile boolean processing=true; in the class declaration or set it in the constructor. That guarantees it will be set by the end of the constructor (takes place in the controlling thread) and must be before stopProcessing() is called.
Your application is (of course) a toy but think about when you would stop the threads the user didn't stop.
It's bad practice to just end the JVM without bringing all threads to a safe conclusion.
That doesn't matter in your toy but in real applications you may want to release external resources and (say) flush file buffers rather than let the JVM pull the run out.
That is, finally call stopProcessing() on all the threads in one loop and then join() in a second loop before ending the application.
It's important to use two loops because it makes sure the threads are all stopping concurrently and not one after the other.
I can't emphasise enough why you should end threads properly. People often ignore me and then long into to development have weird glitches that difficult to localise and hard to drive out.
Other considerations:
Consider using interrupt(). It's designed to help terminate threads and does nice things for you like jump them out of sleep and wait conditions (with an Interrupted exception). That will mean they may terminate faster (never slower) than your approach.
Again, not relevant in a toy but valuable in serious application.
Consider sub-classing Runnable instead of Thread. Again your toy is fine and valid but again 'real' applications end up preferring Runnable and using a thread pool of some kind (e.g. ExecutorService). That's clever because on many platforms the overhead of creating and destroying Threads is far larger than a lighter-weight Runnable.
That's the standard advice but I don't think its wisdom is always explained.

The threads probably haven't started by the time you enter the loop in main. Their states are Thread.State.NEW when you check arrayOfThreads[i].getState().
A simple solution would be either to wait some time before executing the loop to make sure the threads are running or to run a while loop over your loop to check the condition more than once.
Both are spotty and inefficient because you don't know exactly when the thread will be up and running. Instead, I would advise implementing a wait-notify mechanism to show a dialogue when the thread is certainly running.

Related

Thread synchronisation using semaphores

This was an interview question , any help would be appreciated
How do you synchronize two threads, out of which one increments a value and the the other displays it ( P.S. the thread which displays the value must only display a value when its a new value )
Ex : int x = 5;
T1 : increments it to 6
T2 : must display 6 ( only once ) and must display it again when it becomes 7
I answered that I would use a semaphore something like:
int c=0; // variable that I used to synchronize
// In T1
if( c = 0 )
{
c++;
x++; // value that is incremented
}
// in T2
if( c == 1 )
{
cout<<x;
c--;
}
He then asked what would you do if there's a context switch from thread T1 to T2 after setting c to 1 but before incrementing x ( As in that case it would enter P2 before incrementing x )
I couldn't answer this part. Any help would be appreciated.
This is a classic use case for a condition variable with the slight hitch that the value can easily update more than once in thread 1 before thread 2 runs to handle it:
// In some scope common to both threads
int c_ = 0; // variable
std::mutex mutex_();
std::condition_variable cond_();
// Thread 1
{
std::lock_guard<std::mutex> lock(mutex_);
++c_;
}
cond_.notify_one();
// Thread 2
{
std::lock_guard<std::mutex> lock( mutex_ );
int cLocal = c_;
while ( !done ) {
cond_.wait( lock, [] { return c_ != cLocal; } );
while ( cLocal++ < c_ )
... // Display new *local* value
}
}
Nice exercise.
You haven't specified the c++ tag in the question, but the question itself contains cout<<x, so you were probably interviewing for a C++ position. Despite that, I'm going to answer in Java since this is an interview question and language shouldn't matter much as long as I avoid using anything too specific to Java.
As your interviewer pointed out, the synchronization has to happen in both directions:
The printing thread must wait for the incrementing thread to finish its job
The incrementing thread must wait for the printing thread to finish its job
So we need something to let us know that the printer is done (so the incrementer can run), and another to let us know that the incrementer is done. I used two semaphores for that:
Working version on Ideone
import java.util.concurrent.Semaphore;
class IncrementDemo {
static int x = 0;
public static void main(String[] args) {
Semaphore incrementLock = new Semaphore(0);
Semaphore printLock = new Semaphore(0);
Thread incrementer = new Thread(() -> {
for(;;) {
incrementLock.acquire(); //Wait to be allowed to increment
x++;
printLock.release(); //Allow the printer to print
}
});
Thread printer = new Thread(() -> {
for (;;) {
incrementLock.release(); //Let the incrementer to its job
printLock.acquire(); //Wait to be allowed to print
System.out.println(x);
}
});
incrementer.setDaemon(false); //Keep the program alive after main() exits
printer.setDaemon(false);
incrementer.start(); //Start both threads
printer.start();
}
}
(I removed the try/catch blocks around acquire for readability).
Output:
1
2
3
4
5
6
7
...
Problems:
There are 2 main problems with parallel code in general.
1. Atomicity
The smallest granularity in code are in fact not the single operations like i++, but the underlying assembly-instructions. Therefore every operation, which involves a write, may not be called from multiple threads. (this differs heavily on your target architecture, but x86 is in contrast to arm64 very restrictive)
But luckily c++ provides the std::atomic operations, which give you a nice plattform independent way to modify variables from multiple threads.
2. Consistency
Both the compiler and the processor are allowed to reorder any instruction as long the consistency of the local thread is preserved. So what does this mean?
Take a look at your first thread
if( c = 0 )
{
c++;
x++; // value that is incremented
}
You have 3 operations c == 0, c++ and x++. Both increments do not depend from each other, hence the compiler would be allowed to swap them. At runtime the core may reorder them too, leaving you in very vague situation. In a sequential world this is perfectly fine and improves the overall performance (unless it leads to security holes like meltdown). Unfortunately neither the compiler or the cpu recognize parallel code, therefore any optimization may break your parallel program.
But once again, c++ provides a built-in solution for this problem called std::memory_order, which enforces are specific consistency-model.
Solutions:
Simple mutex:
A mutex is a simple, but powerfull tool. It solves the problems with Atomicity and Consistency by providing so called critical sections, which prevent parallel execution. This means, that in the given example the if-clause in both threads are sequential and will never be executed in parallel.
The implementation works, but has a flaw. If one of the threads is very slow, the other one will waste a lot of cpu-time by continous checking the newValue flag.
#include <mutex>
std::mutex mutex;
int value = true;
bool newValue = false;
void producer_thread() {
while(true) {
std::lock_guard<std::mutex> lg(mutex);
if (newValue == false) {
value++;
newValue = true;
}
}
}
void consumer_thread() {
while(true) {
std::lock_guard<std::mutex> lg(mutex);
if (newValue == true) {
std::cout << value;
newValue = false;
}
}
}
Condition Variable:
A condition variable is basically just a "wait-for-notify"-construct. You can block the current execution by calling wait until an other thread calls notify. This implementation would be the go-to scenario.
#include <mutex>
#include <condition_variable>
std::mutex mutex;
std::condition_variable cond;
int value = true;
bool newValue = false;
void producer() {
while(true) {
std::unique_lock<std::mutex> ul(mutex);
while (newValue == true) {
cond.wait(ul);
}
value++;
newValue = true;
cond.notify_all();
}
}
void consumer() {
while(true) {
std::unique_lock<std::mutex> ul(mutex);
while (newValue == false) {
cond.wait(ul);
}
std::cout << value;
newValue = false;
cond.notify_all();
}
}

How do I check how many events are happening within 2 seconds? (timer)

I need to check how many events are detected within 2 seconds. I have the timer working and I have everything else working...but I ran into a problem: the loop only checks one time, per second and I can't seem to figure out how to fix that. I need it to check constantly during these two seconds to see how many events there were in total!
Here is what I have:
int seconds = 0;
System.out.println("Seconds: " + seconds);
while(seconds < 2)
{
//Wait 1 second
try {
Thread.sleep(1000);
}
catch(Exception e) {}
seconds++;
System.out.println("Seconds: " + seconds);
//This needs to be looping the whole time.
//But right now, it's being blocked and only checked once
if(eventDetected() && seconds <= 2){
events++;
}
}
So you can see my problem. I can't split them up because then the second timer would run, and THEN eventDetected() would be checked. I need it to check constantly DURING the two second timer...so I basically need both things to happen at once. Is there any way I can do this?
Thanks for any help ahead of time!
I think your design pattern needs work -- I don't know what type event you're looking to detect, but no matter how short your sleep time is, there's a chance you could miss an event using the current pattern. Here's what I suggest:
Have eventDetected() increment your events counter. That way, you won't miss an event.
Then, you just need a way to turn on and off listening (and perhaps resetting the event counter). If you're sure that in you're current pattern you are really in a different thread that won't block your eventDetected() method, you could set a flag to check. For example:
When you want to start listening:
listenForEvents = true;
In eventDetected():
if (listenForEvents) { events++; }
When you want to stop listening (for example, after your Thread.sleep() call):
listenForEvents = false;
With multithreading, make sure to watch out for concurrency issues checking and setting the variables, of course.
I would tell you what kind of event I have to keep track of but then I'd have to kill you :D
Answered my own question. Hopefully this will help anyone else out who has a similar problem at some point! I looked up multithreading a bit...
I created a new class EventTimer which implements Runnable, with a public field for seconds:
public class EventTimer implements Runnable{
int seconds;
static int timerThreadCount = 0;
Thread t;
public EventTimer() {
timerThreadCount++;
this.seconds = 0;
t = new Thread(this, "Event Timer");
t.start(); // Start the thread
}
#Override
public void run() {
// TODO Auto-generated method stub
while(seconds < 2)
{
//Wait 1 second
try {
Thread.sleep(1000);
}
catch(Exception e) {
System.out.println("Waiting interupted.");
}
seconds++;
System.out.println("Seconds: " + seconds);
}
}
}
Then I used an instance of the EventTimer, and used a while loop & if statement to solve my problem.
EventTimer t = new EventTimer();
while(t.seconds < 2){
if(eventDetected()) events++;
}
It was actually quite simple! I realize that each iteration of my loop of operation (since the entire code piece above is inside an infinite loop) will create a new EventTimer thread and I will eventually run into memory problems however. How would I close/end a thread after the timer has reached 2 seconds?

Possible to catch the OS doing Context Switching on threads?

I would like to know how to catch a thread being interrupted by a Context Switch in java.
I got two threads running side by side, which are both changing the same int up and down, and I would like for the sake of my report, to know how to catch the switches, and do something. (eg. make a simple System.out when that happens) Thanks!
As far as an application is concerned context switches are invisible - there is no signal or message sent to the application that notifies it.
The only thing that might tip off an application is timing. For example, if you time a tight loop repeatedly, you might be able to (unreliably) detect a context switch that happens as the loop is executed, due to the longer time required in comparison to executions that were not interrupted. Unfortunately, this would only be possible for compiled languages like C. Languages like Java that make use of a virtual machine make it practically impossible to reliably detect something like this because a loop slowing down might be attributed to any number of reasons, like e.g. the garbage collector acting up.
Moreover, keep in mind that any system call - and especially I/O calls like the ones you'd use to log such an event - very often cause an implicit context switch, which could throw off anything you might want to do.
Why would you want to know something like this anyway? And especially from a Java application?
EDIT:
Well, if you are after creating a synchronization problem, here's my version:
public class Test {
public static long count = 0;
public static void main(String[] args) {
for (int run = 0; run < 5; ++run) {
Test.count = 0;
Thread[] threads = new Thread[10];
for (int i = 0; i < threads.length; ++i) {
threads[i] = new Thread(new Runnable() {
public void run() {
for (long i = 0; i < (10 * 1000 * 1000 * 1000); ++i) {
Test.count += 1;
}
}
});
}
for (int i = 0; i < threads.length; ++i) {
threads[i].start();
}
for (int i = 0; i < threads.length; ++i) {
try {
threads[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Test.count);
}
}
}
Here's what I got from a single run:
1443685504
1439908180
1461384255
1477413204
1440892041
Record the thread making the modification.
Every time the int is modified, store the thread that makes the modification. When it differs from the previous thread, make your System.out.
Otherwise, you would need an operating system that allows you to interrupt a context switch. I don't know of an operating system that allows you to do that.
I don't think you can listen events from thread scheduler (part ot OS Core) but you can use pull strategy:
Make some static volatile string field
In every thread read this field(very often)
If field value != "current-thread-name" => print "Context is Switched to "+thread-name
write thread name to field

Why does an IllegalThreadStateException occur when Thread.start is called again

public class SieveGenerator{
static int N = 50;
public static void main(String args[]){
int cores = Runtime.getRuntime().availableProcessors();
int f[] = new int[N];
//fill array with 0,1,2...f.length
for(int j=0;j<f.length;j++){
f[j]=j;
}
f[0]=0;f[1]=0;//eliminate these cases
int p=2;
removeNonPrime []t = new removeNonPrime[cores];
for(int i = 0; i < cores; i++){
t[i] = new removeNonPrime(f,p);
}
while(p <= (int)(Math.sqrt(N))){
t[p%cores].start();//problem here because you cannot start a thread which has already started(IllegalThreadStateException)
try{
t[p%cores].join();
}catch(Exception e){}
//get the next prime
p++;
while(p<=(int)(Math.sqrt(N))&&f[p]==0)p++;
}
//count primes
int total = 0;
System.out.println();
for(int j=0; j<f.length;j++){
if(f[j]!=0){
total++;
}
}
System.out.printf("Number of primes up to %d = %d",f.length,total);
}
}
class removeNonPrime extends Thread{
int k;
int arr[];
public removeNonPrime(int arr[], int k){
this.arr = arr;
this.k = k;
}
public void run(){
int j = k*k;
while(j<arr.length){
if(arr[j]%k == 0)arr[j]=0;
j=j+arr[k];
}
}
}
Hi I'm getting an IllegalThreadStateException when I run my code and I've figured it's because I am trying to start a thread that has already been started. So how could I kill
or stop the thread each time, to get around this problem?
how could I kill or stop the thread each time, to get around this problem?
The answer is, you can't. Once started, a Thread may not be restarted. This is clearly documented in the javadoc for Thread. Instead, what you really want to do is new an instance of RemoveNonPrime each time you come around in your loop.
You have a few other problems in your code.
First, you need to increment p before using it again:
for(int i = 0; i < cores; i++){
t[i] = new removeNonPrime(f,p); //<--- BUG, always using p=2 means only multiples of 2 are cleared
}
Second, you might be multithreaded, but you aren't concurrent. The code you have basically only allows one thread to run at a time:
while(p <= (int)(Math.sqrt(N))){
t[p%cores].start();//
try{
t[p%cores].join(); //<--- BUG, only the thread which was just started can be running now
}catch(Exception e){}
//get the next prime
p++;
while(p<=(int)(Math.sqrt(N))&&f[p]==0)p++;
}
Just my $0.02, but what you are trying to do might work, but the logic for selecting the next smallest prime will not always pick a prime, for example if one of the other threads hasn't processed that part of the array yet.
Here is an approach using an ExecutorService, there are some blanks (...) that you will have to fill in:
/* A queue to trick the executor into blocking until a Thread is available when offer is called */
public class SpecialSyncQueue<E> extends SynchronousQueue<E> {
#Override
public boolean offer(E e) {
try {
put(e);
return true;
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
return false;
}
}
}
ExecutorService executor = new ThreadPoolExecutor(cores, cores, new SpecialSyncQueue(), ...);
void pruneNonPrimes() {
//...
while(p <= (int)(Math.sqrt(N))) {
executor.execute(new RemoveNonPrime(f, p));
//get the next prime
p++;
while(p<=(int)(Math.sqrt(N))&&f[p]==0)p++;
}
//count primes
int total = 0;
System.out.println();
for(int j=0; j<f.length;j++){
if(f[j]!=0){
total++;
}
}
System.out.printf("Number of primes up to %d = %d",f.length,total);
}
class RemoveNonPrime extends Runnable {
int k;
int arr[];
public RemoveNonPrime(int arr[], int k){
this.arr = arr;
this.k = k;
}
public void run(){
int j = k*k;
while(j<arr.length){
if(arr[j]%k == 0)arr[j]=0;
j+=k;
}
}
}
You could implement Runnable instead and use new Thread( $Runnable here ).start() or use a ExecutorService to reuse threads.
* It is never legal to start a thread more than once.
* In particular, a thread may not be restarted once it has completed
* execution.
*
* #exception IllegalThreadStateException if the thread was already started
*/
public synchronized void start() {
In Android, document still mention that we will get IllegalThreadStateException if the thread was already started.
However for some device it will not throw this exception (tested on Kyocera 7.0). In some popular device like Samsung, HTC, it throw throw the exception normally
I answer here because the Android question is mark as duplicated to this question.
Why does an IllegalThreadStateException occur when Thread.start is
called again
Because JDK/JVM implementers coded Thread.start() method that way. Its a reasonable functional expectation to be able to restart a thread after a thread has completed its execution and that is what being suggested in chrisbunney's answer ( and I have put in a comment in that answer ) but if you look at Thread.start() implementation , the very first line is ,
if (threadStatus != 0)
throw new IllegalThreadStateException();
where threadStatus == 0 means NEW state so my guess is that implementation doesn't resets this state to zero after execution has completed & thread is left in TERMINATED state ( non - zero state ). So when you create a new Thread instance on same Runnable , you basically reset this state to zero.
Also, I noticed the usage of word - may & never in same paragraph as different behavior is being pointed out by Phan Van Linh on some OSes,
It is never legal to start a thread more than once. In particular, a
thread may not be restarted once it has completed execution.
I guess what they are trying to say in above Javadoc that even if you don't get IllegalThreadStateException on certain OS, its not legal in Java/Thread class way & you might get unexpected behavior.
The famous thread state diagrams depict the same scenario - no going back from dead state to new.
ThreadPools can be used for delivering tasks to set number of threads. When initiating you set the number of threads. Then you add tasks for the pool. And after you can block until all tasks have finished processing. Here is some sample code.
I am not at all sure I understand the question. All the methods for stopping threads that are executed from other threads are deprecated; the way to stop a thread is to have it check a variable that it and another thread can access (perhaps a volatile variable), and have the running thread check it occasionally to see if it should exit on its own.
I cannot tell why/whether you want to eliminate the running thread and use another one, and I cannot see how the different threads are going to help execute your overall goal any faster. But it's possible I'm just not understanding the math.
The Thread.isAlive() method can tell you if the Thread has already been started. Simply do this where you want to start your thread:
if(!t[p%cores].isAlive()){
t[p%cores].start();
}

Can this Java program ever print a value other than zero?

I have a favorite C# program similar to the one below that shows that if two threads share the same memory address for counting (one thread incrementing n times, one thread decrementing n times) you can get a final result other than zero. As long as n is reasonably large, it's pretty easy to get C# to display some non-zero value between [-n, n]. However, I can't get Java to produce a non-zero result even when increasing the number of threads to 1000 (500 up, 500 down). Is there some memory model or specification difference wrt C# I'm not aware of that guarantees this program will always yield 0 despite the scheduling or number of cores that I am not aware of? Would we agree that this program could produce a non-zero value even if we can not prove that experimentally?
(Not:, I found this exact question over here, but when I run that topic's code I also get zero.)
public class Counter
{
private int _counter = 0;
Counter() throws Exception
{
final int limit = Integer.MAX_VALUE;
Thread add = new Thread()
{
public void run()
{
for(int i = 0; i<limit; i++)
{
_counter++;
}
}
};
Thread sub = new Thread()
{
public void run()
{
for(int i = 0; i<limit; i++)
{
_counter--;
}
}
};
add.run();
sub.run();
add.join();
sub.join();
System.out.println(_counter);
}
public static void main(String[] args) throws Exception
{
new Counter();
}
}
The code you've given only runs on a single thread, so will always give a result of 0. If you actually start two threads, you can indeed get a non-zero result:
// Don't call run(), which is a synchronous call, which doesn't start any threads
// Call start(), which starts a new thread and calls run() *in that thread*.
add.start();
sub.start();
On my box in a test run that gave -2146200243.
Assuming you really meant start, not run.
On most common platforms it will very likely produce non zero, because ++/-- are not atomic operations in case of multiple cores. On single core/single CPU you will most likely get 0 because ++/-- are atomic if compiled to one instruction (add/inc) but that part depends on JVM.
Check result here: http://ideone.com/IzTT2
The problem with your program is that you are not creating an OS thread, so your program is essentially single threaded. In Java you must call Thread.start() to create a new OS thread, not Thread.run(). This has to do with a regrettable mistake made in the initial Java API. That mistake is that the designer made Thread implement Runnable.
add.start();
sub.start();
add.join();
sub.join();

Categories

Resources