Java - does not work in a multithreaded program

I'm still new to java and trying to play learning topics. My question is that it does not loop 5 times. It works once and goes out. I use a.class to lock the class object, so that both threads are blocked on the same monitor of the object.

class a implements Runnable { Thread thr; int count; String time; a(String s) { thr = new Thread(this, s); thr.start(); } public void run() { count++; if (Thread.currentThread().getName().compareTo("one") == 0) { synchronized (a.class) { try { for (int i = 0; i < 5; i++) { System.out.println("Now running thread " + Thread.currentThread().getName() + " with count " + count); time = "Tick"; System.out.println(time); notify(); while (time == "Tock") { wait(); } } } catch (Exception e) { } } } else if (Thread.currentThread().getName().compareTo("two") == 0) { synchronized (a.class) { try { for (int j = 0; j < 5; j++) { System.out.println("Now running thread " + Thread.currentThread().getName() + " with count " + count); time = "Tock"; System.out.println(time); notify(); while (time == "Tick") { wait(); } } } catch (Exception e) { } } } } } public class b { public static void main(String args[]) { a obj1 = new a("one"); a obj2 = new a("two"); } } 
+4
source share
3 answers

Here you go with the source code:

 class a implements Runnable { Thread thr; int count; static String time = "Tock"; a(String s) { thr = new Thread(this, s); thr.start(); } public void run() { count++; if (Thread.currentThread().getName().compareTo("one") == 0) { synchronized (a.class) { try { for (int i = 0; i < 5; i++) { while (time.equals("Tock")) { a.class.wait(); } System.out.println("Now running thread " + Thread.currentThread().getName() + " with count " + count); time = "Tock"; System.out.println(time); a.class.notify(); } } catch (Exception e) { e.printStackTrace(); } } } else if (Thread.currentThread().getName().compareTo("two") == 0) { synchronized (a.class) { try { for (int j = 0; j < 5; j++) { while (time.equals("Tick")) { a.class.wait(); } System.out.println("Now running thread " + Thread.currentThread().getName() + " with count " + count); time = "Tick"; System.out.println(time); a.class.notify(); } } catch (Exception e) { e.printStackTrace(); } } } } } public class Test { public static void main(String args[]) { a obj1 = new a("one"); a obj2 = new a("two"); } } 

The problem was that you called wait and notify on the implicit this object when the lock was held in the a.class object, so you should call wait/notify on a.class . That's all.

I also did a little restructuring, since suppose you wanted them to print Tick and Tock in alternating sequence, right?

+3
source

When comparing strings (and objects in general), you should use equals as opposed to == (which is usually reserved for primitives): while(time.equals("Tock")) . == in lines often leads to false when you want (and think it should) return true , and therefore your loop will exit as expected.

+2
source

The answer to why you only loop around once is that you call notify() on an object that is not locked, and thus an IllegalMonitorStateException is IllegalMonitorStateException and caught by an empty catch statement.

This is one way to do this. Not to say that this is the best. I tried to keep it close to your code:

 public class TickTock { static final int N = 4; Object lock = new Object(); int token; class Worker extends Thread { int id; Worker(int id) { this.id = id; } @Override public void run() { try { synchronized (lock) { for (int i = 0; i < 5; i++) { while (id != token%N) lock.wait(); System.out.println(id + " " + i); token++; lock.notifyAll(); } } } catch (InterruptedException e) { e.printStackTrace(); } } } void start() { for (int i = 0; i < N; i++) { new Worker(i).start(); } } public static void main(String[] args) { new TickTock().start(); } } 
+2
source

Source: https://habr.com/ru/post/1433680/


All Articles