Putting runnable to sleep

I have a problem with Java. I would like to write a program where there is Class Main which has ArrayList of Threads of some class (Class Task) which just writes a letter and the number. Object Main just wakes one Thread from ArrayList and let it to do something while the same object(Main) sleeps another one.

It works ok: 0A, 0B, 0C, 1B, 1C, 1A, 2B, 2A, 2C, 3B, 3C, 3A, 4B, 4C, 4A, 5B, 5A, 5C,

but only if i Comment the: e.printStackTrace() e is Exception then I get lot of java.lang.IllegalMonitorStateException at java.lang.Object.notify(Native Method) at Main.run(Main.java:22)

So the notify works wrong, how I should correctly wake it, please tell me, show, correct. PLease

import java.util.ArrayList;

import java.util.ArrayList;

public class Main extends Thread {
ArrayList<Thread> threads;

public Main() {
    super();
    threads = new ArrayList<Thread>();
}

public void run() {
    for (int i = 0; i < 3; i++) {
        threads.add(new Thread(new Task(i + 65)));
    }
    long cT = System.currentTimeMillis();
    for (int i = 0; i < threads.size(); i++) {
        threads.get(i).start();
    }
    while (System.currentTimeMillis() - cT < 10000) {
        for (int i = 0; i < threads.size(); i++) {
            try {
                threads.get(i).notify();
                // HOW TO WAKE THREAD FROM threads ArrayList
                Thread.sleep(1000);
                // how to put to bed the same thread ?
                threads.get(i).wait();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

public static void main(String[] args) {
     new Main().start();
    //new Thread(new Task(65)).start();

}

}

H

public class Task implements Runnable {
int nr;
char character;

public Task(int literaASCII) {
    this.nr = 0;
    character = (char) (literaASCII);
}

@Override
public void run() {
    while (true) {
        try {
            System.out.print(nr + "" + character + ", ");
            nr++;
            int r = (int) ((Math.random() * 500) + 500); // <500ms,1000ms)
            Thread.sleep(r);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}



public static void main(String[] args) {
    // TODO Auto-generated method stub

}
}

Answers


sleep and wait are very different. sleep simply pauses the current thread for the specified amount of time, and has no direct interaction with other threads.

wait is more complicated: the idea of wait is to pause a thread on a given monitor (or lock, if you wish) and let other thread do work until it notifys on that monitor and releases it. So wait and notify involves interaction between two or more threads.

Because of this interaction, in order for wait and notify to work correctly, the thread which calls those methods must own the monitor (the lock), which means, that object.wait() or object.notify() must be called from within synchronized(object){ ... } block. If you call object.wait() without synchronized-block you will always get an IllegalMonitorStateException.

In your code,

for (int i = 0; i < threads.size(); i++) {
  threads.get(i).start();
} 

this will start all threads and then will run them all at the same time, not one at a time as you want.

To make sure only one thread runs one at a time you will need to pass a common monitor object to all threads and have them wait on that monitor. For example:

public class Main extends Thread {
  //...

  public void run(){
    //Initialize all threads with common monitor object
    Object monitor = new Object();
    for (int i = 0; i < 3; i++) {
      threads.add(new Thread(new Task(i + 65, monitor)));
    }
    long cT = System.currentTimeMillis();
    for (int i = 0; i < threads.size(); i++) {
      //All threads will start, and immediately pause on monitor.wait()
      threads.get(i).start();
    }
    synchronized(monitor){
      while (System.currentTimeMillis() - cT < 10000) {
        //All threads are currently waiting, so we need to wake one random
        //thread up by calling notify on monitor. Other thread will not run yet,
        //because this thread still holds the monitor.
        monitor.notify();

        //Make this thread wait, which will temporarily release the monitor
        //and let the notified thread run.
        monitor.wait();
      }
    }
  }
}

//...

public class Task implements Runnable{
  int nr;
  char character;
  Object monitor;

  public Task(int literaASCII, Object monitor) {
    this.nr = 0;
    this.monitor = monitor;
    character = (char) (literaASCII);
  }

  @Override
  public void run() {
    synchronized(monitor){
      while (true) {
        //Pause this thread and let some other random thread
        //do the work. When other thread finishes and calls notify()
        //this thread will continue (if this thread is picked).
        monitor.wait();

        try {
          System.out.print(nr + "" + character + ", ");
          nr++;
          int r = (int) ((Math.random() * 500) + 500); // <500ms,1000ms)

          Thread.sleep(r);
        } catch (Exception e) {
          e.printStackTrace();
        }

        //This thread has finished work for now. 
        //Let one other random thread know.
        monitor.notify();

        //Other thread will not be able to do work until this thread 
        //releases the monitor by calling monitor.wait() or 
        //completely exists the synchronized(monitor){ ... } block.
      }
    }
  }
}

It may behave slightly differently from your original intention, because threads will wake up randomly, so there is no guarantee the output will be in any particular order.

Also note that in general you should prefer notifyAll() to notify(), unless you have a very good reason to use notify(). Because notify() only wakes up one thread, if that thread "forgets" to call notify at the end, all other threads may wait forever.


In order to call wait() on an object, you have to hold the synchronized lock on that object (though the lock is actually released while the thread is waiting):

You can do the following thing where solution is achived.

import java.util.ArrayList;

public class Main extends Thread {
    ArrayList<Thread> threads;

    public Main() {
        super();
        threads = new ArrayList<Thread>();

        for (int i = 0; i < 3; i++) {
            threads.add(new Thread(new Task(i + 65)));
        }

        for (int i = 0; i < threads.size(); i++) {
            threads.get(i).start();
        }

    }

    public void run() {
        long cT = System.currentTimeMillis();
        while (System.currentTimeMillis() - cT < 10000) {
            for (int i = 0; i < threads.size(); i++) {
                try {
                    synchronized (threads.get(i)) {
                        threads.get(i).notify();
                        // HOW TO WAKE THREAD FROM threads ArrayList
                        Thread.sleep(1000);
                        // how to put to bed the same thread ?
                        threads.get(i).wait();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

    }

    public static void main(String[] args) {
        new Main().start();
        // new Thread(new Task(65)).start();

    }

}

class Task implements Runnable {
    int nr;
    char character;

    public Task(int literaASCII) {
        this.nr = 0;
        character = (char) (literaASCII);
    }

    public void run() {
        while (true) {
            try {
                System.out.print(nr + "" + character + ", ");
                nr++;
                int r = (int) ((Math.random() * 500) + 500); // <500ms,1000ms)
                Thread.sleep(r);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

You need to synchronize on the thread you want to wait():

synchronized(threads.get(i)) {
    // how to put to bed the same thread ?
    threads.get(i).wait();
}

Ok I corected it so it's now: But i get on console

0A, 0B, 0C, 0D, 0E, 1A, 1B, 1C, 1D, 1E, 2A, 2B, 2C, 2D, 2E, I stop 10 I stop 11 I stop 12 I stop 13 I stop 14 I stop 15

But i would rather like sth like 0A,1A(A works for some time for 3000ms) then the other runs for 3 secs etc. not like A,B,C,D,E,A, but more like A,A,A,B,B,B....

But also i just can't kill this threads, there is never ending loop, I'd like to kill it while Main is dying.

Thank you for all your comments

import java.util.ArrayList;

public class Main extends Thread {
ArrayList<Thread> threads;

public Main() {
    super();
    threads = new ArrayList<Thread>();
}

 public void run(){

Object monitor = new Object();
for (int i = 0; i <= 5; i++) {
  threads.add(new Thread(new Task(i + 65, monitor)));
}
long cT = System.currentTimeMillis();
for (int i = 0; i < threads.size(); i++) {
  threads.get(i).start();
}
synchronized(monitor){
  while (System.currentTimeMillis() - cT < 10000) {
      try{

    monitor.notify();
    Thread.sleep(50);


    monitor.wait();}catch(Exception e){e.printStackTrace();}
  }

for(int i = 0; i < threads.size(); i++){
    System.out.println("I suspend "+threads.get(i).getId());
    threads.get(i).stop();
}


}
 }


 public static void main(String[] args) {
     new Main().start();
    //new Thread(new Task(65)).start();

}

}

H

public class Task implements Runnable {
int nr;
char character;
Object monitor;

public Task(int literaASCII, Object monitor) {
    this.nr = 0;
    this.monitor = monitor;
    character = (char) (literaASCII);
}

@Override
public void run() {
    synchronized (monitor) {
        while (true) {

            try {
                monitor.wait();

                System.out.print(nr + "" + character + ", ");
                nr++;
                int r = (int) ((Math.random() * 500) + 500); // <500ms,1000ms)

                Thread.sleep(r);
            } catch (Exception e) {
                e.printStackTrace();
            }

            monitor.notify();

        }
    }
}

}


Need Your Help

Looking for system calls implementation on linux kernel

c linux linux-kernel kernel

I'm looking for the implementations of open(), close(), write() and unlink(), but I can't find them anywhere! Every function I find is like sys_open, do_open, etc_open... but nothing with the inter...

iOS - SimpleFTP How to use SFTP (ssh)?

ios ssh sftp nsstream

I am trying to use Apple's code from their SimpleFTPSample project to upload/list directory in my app. I am able to get it working on a server using just FTP, but I need it to now work on a server ...