0

I am supposed to create 3 threads first will print 'A' every 3 seconds, second 'B' every 4 seconds and 'C' every 5 seconds.

I did it like that but they change their order durign printing and it is suspicous. But I think that in 9th second they can mix... and its fine. Please post yuur opinion.

public class MyThread extends Thread {

    static int ID;
    int id;

    public MyThread() {
        id = ID++;
    }

    public synchronized void run() {
        char character = (char) (65 + id);
        while (true) {
            System.out.println(character);
            try {
                Thread.sleep(3000 + id * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        new MyThread().start();
        new MyThread().start();
        new MyThread().start();
    }
}

Output:

A
B
C
A
B
C
A
B
A
C
B
A
.......
Yoda
  • 17,363
  • 67
  • 204
  • 344
  • 1
    You probably shouldn't be extending `Thread`, rather implementing `Runnable`. Extending `Thread` should generally be avoided. – Boris the Spider Mar 29 '14 at 13:44
  • See [How do I schedule a task to run at periodic intervals?](http://stackoverflow.com/questions/4544197/how-do-i-schedule-a-task-to-run-at-periodic-intervals) – Dave Swartz Mar 29 '14 at 13:45
  • @Yoda See [“implements Runnable” vs. “extends Thread”](http://stackoverflow.com/q/541487/2846923). – The Guy with The Hat Mar 29 '14 at 13:46
  • @BoristheSpider Could you tell why? I also use to extend `Thread`, and I didn't know it is considered a bad practice, why should it be avoided? – BackSlash Mar 29 '14 at 13:46
  • Two reasons. 1) Because it breaks OO - you are not extending the behaviour of `Thread`, you are creating a task for it to run. 2) Because threads themselves exhibit odd behaviour, for example `wait` and `notify` behave differently if locked on a `Thread`. There are some good answers [here](http://stackoverflow.com/q/541487/2071828). – Boris the Spider Mar 29 '14 at 13:46
  • I really don't see the problem here. – The Guy with The Hat Mar 29 '14 at 13:49
  • The output looks ok to me, what part is suspicious? – Joachim Isaksson Mar 29 '14 at 13:51

2 Answers2

2

There is a general issue with using sleep; it schedules between the end of one task the the beginning of the next. Not between the beginning of two tasks.

So, every time your tasks run they fall a little off the time you wanted them to run.

This is generally why sleep is not used for scheduling tasks as a specific rate.

As @Joachim points out, your output looks fine. Here is a quick calculation of when each thread should print:

Timeline spreadsheet

However I would strongly recommend that you use a ScheudledExecutorService as below:

public static void main(final String[] args) throws Exception {
    final ScheduledExecutorService ses = Executors.newScheduledThreadPool(3);
    final class Work implements Runnable {

        private final String name;

        public Work(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            System.out.println(name);
        }
    }
    ses.scheduleAtFixedRate(new Work("A"), 0, 3, TimeUnit.SECONDS);
    ses.scheduleAtFixedRate(new Work("B"), 0, 4, TimeUnit.SECONDS);
    ses.scheduleAtFixedRate(new Work("C"), 0, 5, TimeUnit.SECONDS);
    ses.schedule(new Runnable() {

        @Override
        public void run() {
            ses.shutdown();
        }
    }, 1, TimeUnit.MINUTES);
    ses.awaitTermination(1, TimeUnit.DAYS);
}

With a few Java 8 lambdas:

public static void main(final String[] args) throws Exception {
    final ScheduledExecutorService ses = Executors.newScheduledThreadPool(3);
    ses.scheduleAtFixedRate(() -> System.out.println("A"), 0, 3, TimeUnit.SECONDS);
    ses.scheduleAtFixedRate(() -> System.out.println("B"), 0, 4, TimeUnit.SECONDS);
    ses.scheduleAtFixedRate(() -> System.out.println("C"), 0, 5, TimeUnit.SECONDS);
    ses.schedule(() -> ses.shutdown(), 1, TimeUnit.MINUTES);
    ses.awaitTermination(1, TimeUnit.DAYS);
}
Boris the Spider
  • 59,842
  • 6
  • 106
  • 166
1

Style issues discussed in the comments aside, the output you're showing looks correct;

A    0 seconds, thread start
B    0 seconds, thread start
C    0 seconds, thread start
A    3 seconds
B    4 seconds
C    5 seconds
A    6 seconds (2*3)
B    8 seconds (2*4)
A    9 seconds (3*3)
C   10 seconds (2*5)
B   12 seconds (3*4)
A   12 seconds (4*3)
...
Joachim Isaksson
  • 176,943
  • 25
  • 281
  • 294