Multithreading issue can't wait for thread to finish - java

I am having problem with multithreading.
When I am tring to use wait() and notify() or join() I am getting InterruptedException.
I have 2 threads in a WHILE loop and I want to wait until both of them are finished.
this is my code:
while (!GamePanel.turn)
{
if(GamePanel.s.isRunning)
{
synchronized (GamePanel.s.thread)
{
try {
GamePanel.s.thread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//Player selected random moves
if(GamePanel.selectedMove == 1)
{
//Get computer's Random move.
strategy.getRandomMove();
}
else
{
//Player selected AI moves
if(GamePanel.selectedMove == 2)
{
//Get computer's AI move.
strategy.getMove();
System.out.println(strategy.move);
}
}
//Perform the next move of the computer.
Rules.makeMove(GamePanel.dimples, strategy.move, false);
}
both strategy.getMove() and Rules.makeMove() are threads.
for each thread I've created my own start() and stop() methods :
public void start()
//This function starts the thread.
{
if (!isRunning)
{
isRunning = true;
thread = new Thread(this);
thread.setPriority(Thread.NORM_PRIORITY);
thread.start();
}
}
private void stop()
//This function stops the thread.
{
isRunning = false;
if (thread != null)
{
thread.interrupt();
}
thread = null;
}
I have also tried to do thread.stop() but still same problem.
My question is how can I make the WHILE loop to wait until both threads are done??

You might consider to switching your code to use a CountDownLatch. You would create the latch like the following and all 3 threads would share it:
final CountDownLatch latch = new CountDownLatch(2);
Then your two threads would decrement the counter as they finish:
countDown.countDown();
And your waiting thread would do:
countDown.await();
It would be awoken after both of the threads finish and the latch goes to 0.

Related

How kill a thread or stop a Thread?

My Java code creates a thread on button click.
Every time if the button is clicked a thread is created.
I want to kill the previous thread if button is clicked again.
how can I do this?
below is the portion of code inside buttonclicklistener
myThread= new Thread()
{
public void run() {
diff2 = Math.abs(d3.getTime() - d1.getTime());
long diffseconds = diff2 /1000;
final long start = System.currentTimeMillis()/1000;
tv_timecount=(TextView)findViewById(R.id.tv_timeCount);
while(diffseconds>0)
{
tv_timecount.setText(String.valueOf(diffseconds--));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(myThread.isInterrupted())
break;
}
}
};
myThread.start();
I want to stop this Thread.
Many ways,
1: Using deprecated stop
Thread t = new Thread();
t.start();
t.stop(); //this is deprecated but it stops the thread
2: Using interrupt
Thread t = new Thread();
t.start();
t.interrupt();
3: Killing a thread with a while loop
boolean running = true;
Thread t = new Thread(() -> {
while (running) {
System.out.println("Running");
try { Thread.sleep(100); } catch (Throwable t) {}
}
});
t.start();
running = false;
You didn't mention why exactly you can't stop the thread, so I've some assumes which problems you might have.
1.Main reason why interrupt doesn't work in your code is because you catch InterruptedException and do noghing about that. But you should set interrupted flag by yourself after that, using Thread.currentThread().interrupt()
2.You can click the button 2 or more times at the same time, so all the clicks will try to stop the same thread, but every of them then start their own thread, so all but one of these thread (or pointer to them) will leak from you. This can be solved using synchronized function.
The general code, which handles button click should be looking like the code below:
private Thread myThread;
private synchronized void buttonClick() throws InterruptedException //NOTE synchronized
{
if (myThread != null) {
myThread.interrupt();
myThread.join();
}
myThread = new Thread(() -> {
diff2 = Math.abs(d3.getTime() - d1.getTime());
long diffseconds = diff2 / 1000;
final long start = System.currentTimeMillis() / 1000;
tv_timecount = (TextView) findViewById(R.id.tv_timeCount);
while (diffseconds > 0) {
tv_timecount.setText(String.valueOf(diffseconds--));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // NOTE: flag interrupt gets set
}
if (myThread.isInterrupted())
break;
}
});
}
Best way would be to use a flag. Introduce a flag inside your while method Add logic to check if flag is set and only then execute the code in your while loop.
while(diffseconds>0)
{
synchronized(Object.class){
if(flag == set) break;
}
//your code
}
You can reset/set flag on button click from other threads or the main execution.

Is there a quick way to close a thread before the main code continues?

I have a students working on a Simon Game for a final project at school and I have tried all day to solve her problem.
She is trying to create the game Simon. The program randomly selects a sequence of colours and highlights those colours by changing the colours of the 4 coloured buttons from the regular colour to white for a few seconds and then back.
Instead of highlighting one colour at a time white, the programming is making all colours appear white at the same time. So users don't know the sequence.
I have been looking up issues with running multiple threads and have tried using the .join() function. However, when that is used no colours turn white.
//highlights the colours that are currently in the array
public void play() {
//loop through the array and look at all the colours so far
for(int i=0; i<round;i++){
//red is the position in the array
if(colours[i]==1){
Thread sleep=new Thread(new Runnable(){
#Override
public void run(){
//change the colour of the red button to white
redButton.setBackground(Color.WHITE);
redButton.setOpaque(true);
//wait
try {
Thread.currentThread().sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
//change the colour back
redButton.setBackground(Color.RED);
redButton.setOpaque(false);
}
});
sleep.start();
}
//yellow
else if(colours[i]==2){
Thread sleep=new Thread(new Runnable(){
#Override
public void run(){
yellowButton.setBackground(Color.WHITE);
yellowButton.setOpaque(true);
try {
Thread.currentThread().sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
yellowButton.setBackground(Color.YELLOW);
yellowButton.setOpaque(false);
}
});
sleep.start();
}
//green
else if(colours[i]==3){
Thread sleep=new Thread(new Runnable(){
#Override
public void run(){
greenButton.setBackground(Color.WHITE);
greenButton.setOpaque(true);
try {
Thread.currentThread().sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
greenButton.setBackground(Color.GREEN);
greenButton.setOpaque(false);
}
});
sleep.start();
}
//blue
else if(colours[i]==4){
Thread sleep=new Thread(new Runnable(){
#Override
public void run(){
blueButton.setBackground(Color.WHITE);
blueButton.setOpaque(true);
try {
Thread.currentThread().sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
blueButton.setBackground(Color.CYAN);
blueButton.setOpaque(false);
}
});
sleep.start();
}
}
}
the code there basically says.
for all the steps in the sequence start a thread each.
then each of those threads (all started very soon after each other and not before the previous completes.) set the background to white for 1 second then back.
Usually you want to update the ui in the background so that you can continue to interact, but in this case you are playing a sequence and don't want any input. if updating in the background is required put the whole loop in a thread and you will want to sleep between iterations of that loop. otherwise just do it in the main thread. once the sequence is done playing for the user it will pass control back to the event loop to wait for presses.
also the delay should be .3s < t < .5s 1 second is too long
While you want to change the color of each button for 1 second, your main thread is too fast and finish within that second. Thats why it seems all lights change at same time.
Simple solution is to also to make the outer thread sleep for some time but that will not gurantee sequence of the threads. I would suggest to use java.util.concurrent.CountDownLatch to make the outer thread wait for inner thread to finish.
for (int i = 0; i < round; i++) {
CountDownLatch countDownLatch = new CountDownLatch(1);
// red is the position in the array
if (colours[i] == 1) {
Thread sleep = new Thread(new Worker(redButton, Color.RED, countDownLatch))
sleep.start();
}
// yellow
else if (colours[i] == 2) {
Thread sleep = new Thread(new Worker(yellowButton, Color.YELLOW, countDownLatch))
sleep.start();
}
// green
else if (colours[i] == 3) {
Thread sleep = new Thread(new Worker(greenButton, Color.GREEN, countDownLatch))
sleep.start();
}
// blue
else if (colours[i] == 4) {
Thread sleep = new Thread(new Worker(blueButton, Color.CYAN, countDownLatch))
sleep.start();
}
countDownLatch.await();
}
}
class Worker implements Runnable {
Button button;
Color color;
CountDownLatch countDownLatch;
public Worker(Button button, Color color, CountDownLatch countDownLatch) {
this.button = button;
this.color = color;
this.countDownLatch = countDownLatch;
}
#Override
public void run() {
button.setBackground(Color.WHITE);
button.setOpaque(true);
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
button.setBackground(color);
button.setOpaque(false);
countDownLatch.countDown();
}
}
As soon as the light changes color for 1 second you count down the latch using countDownLatch.countDown() you wait for count down to hit zero with countDownLatch.await() in outer thread.

Runnable inside Runnable [duplicate]

This question already has an answer here:
nested postDelayed / Runnable / Handler Android
(1 answer)
Closed 4 years ago.
Basically , i have 5 Runnables for each user.
Inside each Runnable, There must be waiting for a variable to change until it continues. I'll be using either a Semaphore or a CountDownLatch.
So inside each Runnable there is a runnable for waiting.
Here's an example. r1 is a runnable supposed to be user so never ending.
final Handler handler = new Handler();
Runnable r1 = new Runnable() {
#Override public void run() {
// here must be another runnable for waiting
Runnable r2 = new Runnable() {
#Override public void run() {
if (condition) {
latch.countDown();
// ending the runnable
handler.removeCallbacks(r2);
} else {
// keep waiting
handler.postDelayed(r2, 1000);
}
}
}
latch.await();
// restarting the runnable
handler.postDelayed(r1, 1000);
}
}
The problem when using latch.await() is that is running in main thread so blocking the UI.
Any idea how to starts those runnable in different threads?
What i wanted to do is a non stop running Thread that somewhere needs to wait a variable to change so it continues other instructions. Somewhere in the UI when a button is clicked ,a semaphore gets incremented. And in the thread it waits until it is available. Here's the solution i made
Semaphore sem = new Semaphore(0,true);
//somewhere in UI sem.release();
Thread thread = new Thread()
{
#Override
public void run() {
try {
while(true) {
sleep(1000);
semaphore.acquire();
// when updating the UI is needed
runOnUiThread(new Runnable() {
#Override
public void run() {
// work
}
});
}
} catch (InterruptedException e) {
}
}
}

Calling and using the .interrupt() method?

How exactly do i call the .interrupt() method? When I have Thread.sleep(1000), when and where do I call the .interrupt() method? is it after? What I want to do is stop Thread.sleep(1000) midway.
EDIT::
i'm having trouble stopping a thread in the middle. This is part of my code, in the StoplightThread class I have problems on the first if statement. What it is supposed to do is wait at least 10 secs then allow the user to press the button so they can change the light, if the button is pressed it should stop the running thread in this case Thread.sleep(40000). What happens is when I press the button it changes the light but does not stop the thread. If I press the button while there is still 20secs left it will add 20secs to the 10secs for the yellow light, making it yellow for 30 secs.
Edit: if you are wondering, stoplightCanvas.x == 3 is green, stoplightCanvas.x == 2 is yellow, and stoplightCanvas.x == 1 is red.
class StoplightCanvas extends Canvas implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == cross) {
isPressed = true;
if (x == 3 && canCross)
x = 2;
}
repaint();
}
}
class StoplightThread extends Thread
{
StoplightCanvas stoplightCanvas;
StoplightThread(StoplightCanvas stoplightCanvas) {
this.stoplightCanvas = stoplightCanvas;
}
public void run()
{
if (stoplightCanvas.x == 3){
Thread.sleep(10000);
stoplightCanvas.canCross = true;
Thread.sleep(40000);
if(stoplightCanvas.isPressed)
StoplightThread.interrupt();
} else if (stoplightCanvas.x == 2) {
Thread.sleep(10000);
} else if (stoplightCanvas.x == 1) {
Thread.sleep(60000);
}
} catch (InterruptedException e){}
stoplightCanvas.toggleColor();
stoplightCanvas.repaint();
}
}
}
If you were going to call interrupt() at all, you'd call it from a different thread than the sleep().
If you want to interrupt the sleep() midway from the same thread, you can do this:
Thread.sleep( 500 );
...
Thread.sleep( 500 );
All that said, sleep() can be a code smell.
EDIT (after OP edit):
Call interrupt() on the StoplightThread from the GUI thread in your actionPerformed() method.
try this example
public class Test1 {
public static void main(String[] args) throws Exception {
Thread t = new Thread() {
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t.start();
Thread.sleep(1000);
t.interrupt();
}
}
it prints
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at test.Test1$1.run(Test1.java:9)
You need a reference to the thread you want to interrupt, so that you can call interrupt() on it from a different thread.

java: stop thread on ESC

I am writing a simple game in Java, and I have a following issue:
I have a controlling class, called MainGameFrame, in which there is initialized gameThread. MainGameFrame has a key listener for Esc key, so that it pauses/resumes gameThread. However, this doesn't work:
public void keyPressed(KeyEvent e) {
// pause the game
synchronized(gameThread) {
if(e.getKeyCode() == e.VK_ESCAPE) {
try {
if(gameThread.getState() == Thread.State.WAITING) {
System.out.println("continue");
gameThread.notify();
System.out.println("after continue");
} else {
System.out.println("pause");
gameThread.wait();
System.out.println("after pause");
}
} catch (InterruptedException ex) {
Logger.getLogger(MainGameFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
It will pause on Esc and output "pause", but not "after pause".
gameThread.wait() doesn't make the gameThread thread to pause. It makes the current thread (i.e. the event dispatch thread) to wait. Since the EDT is waiting, it can't receive a keypressed event anymore: the entire GUI freezes
Read the Java tutorial on concurrency, and particularly the following page: http://download.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
You should probably change the value of an AtomicBoolean variable, which is regularly inspected by the game thread to know if it has to pause. The game thread would then wait on a shared lock object. When resuming, change the boolean variable again and notify the game thread.
It waits until another thread calls notify(). Your not doing that, so "after pause" is never printed.
What do you want to achieve with gameThread.wait()?
You have the idea of wait and notify backwards.
One thread can not directly pause, or kill another thread. You can, however, change a variable that is shared between threads. When the interested thread sees that the variable has changed it may "pause" itself.
private static volatile boolean paused = false;
private static ReentrantLock pauseLock = new ReentrantLock();
private static Condition unpaused = pauseLock.newCondition();
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
if (!paused)
paused = true;
else {
pauseLock.lock();
try {
paused = false;
unpaused.signal();
} finally {
pauseLock.unlock();
}
}
}
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(200,200));
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
Thread gameThread = new Thread() {
public void run() {
while (true) {
System.out.println("running");
// presumably the game rendering loop
if (paused) {
pauseLock.lock();
try {
try {
unpaused.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
pauseLock.unlock();
}
}
}
}
};
gameThread.start();
}
I would also avoid using wait and notify directly as there are some caveats you must be aware of when using wait & notify (such as your thread that is waiting actually has to wait inside a loop because it can be woken up without notify ever being called).
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4308396
You should also be sure to always acquire and release locks in the following pattern, if not using synchronized blocks:
l.lock();
try {
// code
} finally {
l.unlock();
}
http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Lock.html
I'd also recommend reading:
http://www.javaconcurrencyinpractice.com/
There are more pitfalls than you would think when doing concurrent programming in Java.
The reason that one can not pause or kill a thread from another thread is that the thread doing the pausing or killing has no idea where in execution the other thread is and what resources the other thread might hold.
What would happen if Thread A paused Thread B and Thread B happened to hold several resources that Thread A will need later? What happens if Thread A kills Thread B while Thread B is using a resource that it is supposed to do some special clean up on?

Categories

Resources