5

Using two threads you should print "Hello World Hello World Hello World Hello World Hello World Hello World ".

In two threads one should print "Hello: and another thread "World".

I can do this with different classes such as one each for hello and world I can also do it with an inner class

Is there a way such that there's only one main class and and no inner class?

neatnick
  • 1,489
  • 1
  • 18
  • 29
JaiRathore
  • 53
  • 1
  • 4

3 Answers3

4

Is there a way such that there's only one main class and and no inner class?

Sure. You could pass in the string to print into your Main class. Of course the tricky part is to coordinate the threads so they actually print out "HelloWorld" instead of "WorldHello" or other permutations. The threads are going to run in parallel with no guarantee of order. That's the whole point of threaded programs -- they run asynchronously. Trying to force a particular word output negates the purpose of using threads.

<rant> This smacks to me of a poorly designed computer science assignment. The whole point of writing with threads is that they run independently in parallel. Coordination typically happens when each thread is pulling from a work queue and then putting results into a results queue or something. Anytime you have a threaded program that needs to coordinate this much, you should most likely not be using threads. </rant>

But, since everyone is down-voting my previous answer probably because it doesn't solve their homework problem perfectly, I'll add some logic to coordinate between the two threads and spit out "Hello World...".

The two threads need to be able to lock on something, signal each other, and know when they should be waiting or printing. So I'll add a boolean printHello and will lock on a common lock object that is passed in:

public class HelloWorld implements Runnable {

    private static boolean printHello = true;

    private final String toPrint;
    private final boolean iPrintHello;
    private final Object lock;

    public static void main(String[] args) {
        final Object lock = new Object();
        // first thread prints Hello
        new Thread(new HelloWorld("Hello ", true, lock)).start();
        // second one prints World
        new Thread(new HelloWorld("World ", false, lock)).start();
    }

    public HelloWorld(String toPrint, boolean iPrintHello, Object lock) {
        this.toPrint = toPrint;
        this.iPrintHello = iPrintHello;
        this.lock = lock;
    }

    @Override
    public void run() {
        // don't let it run forever
        for (int i = 0; i < 1000 && !Thread.currentThread().isInterrupted(); ) {
            // they need to synchronize on a common, constant object
            synchronized (lock) {
                // am I printing or waiting?
                if (printHello == iPrintHello) {
                    System.out.print(toPrint);
                    // switch the print-hello to the other value
                    printHello = !printHello;
                    // notify the other class that it can run now
                    lock.notify();
                    i++;
                } else {
                    try {
                        // wait until we get notified that we can print
                        lock.wait();
                    } catch (InterruptedException e) {
                        // if thread is interrupted, _immediately_ re-interrupt it
                        Thread.currentThread().interrupt();
                        return;
                    }
                }
            }
        }
    }
}
Gray
  • 115,027
  • 24
  • 293
  • 354
  • The comments are very helpful. Any thread object that `lock` was passed into is synchronized to it, which means it (the `lock`) will manage when the thread can run. What if there was 3 threads? Is there a way I'd be able too specify the thread? I looked at `notify()` documentation, and it says the next thread is chosen by default, and there isn't an overloaded method. – Honinbo Shusaku Jul 28 '15 at 16:07
  • If there were more than 1 thread, you could call `notifyAll()` and they would all wake up and see if they should print @Abdul. I really hate using `notifyAll()` because typically any thread should be able to do the processing, but in this strange example, it works. – Gray Jul 28 '15 at 19:10
1

How does this look? No thread has specific responsibility for a particular word but with the use of a couple of Atomics it is easy to ensure the threads are in lock-step.

This algorithm does not rely on there being only two treads - as you can see it still works with any number of threads, 42 in this case. It will still work fine with just 2, or even 1.

public class HelloWorld implements Runnable {
  // The words.
  private final String[] words;
  // Which word to print next.
  private final AtomicInteger whichWord;
  // Cycles remaining.
  private final AtomicInteger cycles;

  private HelloWorld(String[] words, AtomicInteger whichWord, AtomicInteger cycles) {
    // The words to print.
    this.words = words;
    // The Atomic holding the next word to print.
    this.whichWord = whichWord;
    // How many times around we've gone.
    this.cycles = cycles;
  }

  @Override
  public void run() {
    // Until cycles are complete.
    while ( cycles.get() > 0 ) {
      // Must transit from this word
      int thisWord = whichWord.get();
      // to the next word.
      int nextWord = thisWord + 1;
      // Are we cycling?
      boolean cycled = false;
      if ( nextWord >= words.length ) {
        // We cycled!
        cycled = true;
        // Back to zero.
        nextWord = 0;
      }
      // Grab hold of System.out to ensure no race there either.
      synchronized ( System.out ) {
        // Atomically step the word number - must still be at thisWord for the step calculations to still be correct.
        if ( whichWord.compareAndSet(thisWord, nextWord)) {
          // Success!! We are the priveliged one!
          System.out.print(words[thisWord]);
          // Count the cycles.
          if ( cycled ) {
            // Just step it down.
            cycles.decrementAndGet();
          }
        }
      }
    }
  }

  public static void test() throws InterruptedException {
    // The words to print.
    String [] words = {"Hello ", "world. "};
    // Which word to print next (start at 0 obviously).
    AtomicInteger whichWord = new AtomicInteger(0);
    // How many cycles to print - 6 as specified.
    AtomicInteger cycles = new AtomicInteger(6);
    // My threads - as many as I like.
    Thread [] threads = new Thread[/*2*/42];
    for ( int i = 0; i < threads.length; i++ ) {
      // Make each thread.
      threads[i] = new Thread(new HelloWorld(words, whichWord, cycles));
      // Start it.
      threads[i].start();
    }
    // Wait for them to finish.
    for ( int i = 0; i < threads.length; i++ ) {
      // Wait for completion.
      threads[i].join();
    }
  }

  public static void main(String args[]) throws InterruptedException {
    System.out.println("HelloWorld:Test");
    test();
  }

}
OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
0
  1. if you want that T1 prints "Hello" and T2 prints "World", and your expected result is "Hello World Hello World Hello World Hello World Hello World Hello World "

    T1 have start by first, T2 is called by T1, otherwise you can have "World Hello Hello Hello World" as output.

    I suggest to customize a reader/writer or producer/consumer structure, using notify() or notifyAll() method to wake up other threads.

  2. If you don't take care about format of output, using Runnable interface and your preferred implementation.

Giorgio Desideri
  • 169
  • 1
  • 12