0

I have a question regarding static synchronized methods and class level locking. Can someone please help me in explaining this example:

class Test
{
    synchronized static void printTest(int n)
    {
        for (int i = 1; i <= 10; i++) {
            System.out.println(n * i);
            try {
                Thread.sleep(400);
            } catch (Exception ignored) {}
        }
    } 
}  

class MyThread1 extends Thread
{
    public void run()
    {
        Test.printTest(1);
    }
}

class MyThread2 extends Thread
{
    public void run()
    {
        Test.printTest(10);
    }
}

public class TestSynchronization
{
    public static void main(String[] args)
    {
        MyThread1 t1 = new MyThread1();
        MyThread2 t2 = new MyThread2();
        t1.start();
        t2.start();
    }
}

Question:

When thread t1 is in the middle of loop (inside printTest()) and I want to make it stop the execution and transfer the control to thread t2. Is there any way to do it?

Since we deal with class level lock I believe we cannot use object level wait() and notify() methods here which would release the object level lock. But in case of class level lock, how to release it and give the control to some other waiting thread?

How do we notify a second thread which is waiting for a class level lock held by thread 1 in the middle of execution?

Sean Bright
  • 118,630
  • 17
  • 138
  • 146
RPR
  • 3
  • 5
  • 2
    When asking for help, please format your code in a readable, consistent way, using any of the standard forms of brace placement and indentation, but ideally one along the lines of the one used in the Java tutorials. Stacking up a bunch of `}` on the same line is the least readable, least maintainable thing I've seen in years. Whoever it is promoting it (this is not the first example I've seen) should be taken out back and beat about the head and shoulders with a wet noodle and made to chant "I do not hate the people who have to work on my code after me" 500 times. – T.J. Crowder Apr 27 '17 at 15:44
  • 2
    Thanks . I am still experimenting on how to post in stackoverflow. This is my first post. I will make it more readable – RPR Apr 27 '17 at 15:47
  • 1
    There are multiple ways to communicate among threads. Without more details about what you're trying to do, we cannot recommend the best approach. See the [java.util.thread package](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/package-summary.html) for a variety of classes that assist communication among threads, including, for example, LinkedBlockingQueue and CountDownLatch. – Andy Thomas Apr 27 '17 at 15:53
  • Thanks Andy. I think my question is clear. Let me expand the question more. There is one thread (t2)waiting on a class level lock held by another thread (t1). So is it possible for t1 thread to notify thread t2 before t1 exits from the static synchronized method. For example when t1 prints 5 in the above example I want to transfer the control to t2. Is it possible? – RPR Apr 27 '17 at 15:58
  • Calling `Thread.sleep()` from inside a `synchronized` block is almost always a really bad idea. In fact, doing anything that takes more than a tiny fraction of a blink of an eye inside `synchronized` is usually a bad idea. The only exception to that would be a `wait()` call that releases the lock, but you should be trying to avoid using `wait()` if you can. – Solomon Slow Apr 27 '17 at 16:49
  • "When thread t1 is in the middle of loop (inside printTest()) and I want to make it stop the execution and transfer the control to thread t2." Do you want `t1` to exit the `printTest()` method, or pause to let `t2` execute, and resuming when `t2` is finished? – erickson Apr 27 '17 at 16:53
  • Calling `Thread.sleep()` *in general* is usually a terrible idea. Synchronized blocks and `wait()`/`notify()` are very primitive operations that don't give you much actual control. As Andy points out, the java.util.concurrent package is much better suited to threading issues more complicated than simple mutex. – markspace Apr 27 '17 at 16:53
  • I think the OP still needs to clarify their question. The OP says "middle of the loop" in the Q but later in the comment says "before [exit of] the static synchronized method." Two different things, really. And I'd like to know why synchronized is used here and NOT something from the concurrent package. Just an "exercise for the reader"? – markspace Apr 27 '17 at 16:59
  • @markspace, If "something from java.util.concurrent" means higher-level synchronization objects (e.g., blocking queues), that's one thing, but if you're talking about the `Lock` interface: That's a sharper tool than `synchronized`. It has more power to solve problems, but it also has more power to bite the programmer---especially a new programmer who's just learning about threads. – Solomon Slow Apr 27 '17 at 17:24
  • @jameslarge Fair enough. I've never used Lock directly so I wasn't thinking about that one. Must of the object from java.util.concurrent are easier to use. The best I think is some form of `BlockingQueue` which makes exchanging information very easy. `Semaphore` and `CountDownLatch` are also fairly easy. – markspace Apr 27 '17 at 17:27

3 Answers3

3

interrupt() can be used here for your requirement.

If your requirement gets change in future and execution of first thread is required after the second thread then remove if(Thread.interrupted()) inside printTest

 class Test {
    synchronized static void printTest(int n) {
        for (int i = 1; i <= 10; i++) {
            if(Thread.interrupted())
                break;
            System.out.println(n * i);
            try {
                Thread.sleep(400);
            } catch (Exception e) {
            }
        }
    }
 }

 class MyThread1 extends Thread {
    public void run() {
        Test.printTest(1);
    }
 }

 class MyThread2 extends Thread {
    public void run() {
        Test.printTest(10);
    }
 }

 public class TestSynchronization {
    public static void main(String t[]) throws InterruptedException {
        MyThread1 t1 = new MyThread1();
        MyThread2 t2 = new MyThread2();
        t1.start();
        t2.start();

        t1.interrupt();
        t1.join();
    }

 }
Pardeep
  • 945
  • 10
  • 18
2

Since we deal with class level lock I believe we cannot use object level wait() and notify()

I try to avoid saying "class level" or "object level." Whenever you use synchronized you are synchronizing on some object. Remember: Test.class is an object: It's the object that contains all of the run-time information that describes the Test class.

When you say "class level locking", what you're really talking about is synchronizing on a global singleton object (the class object), as opposed to "instance level locking" where there may be many different instances of the class that can be independently synchronized.

I want to make it stop the execution and transfer the control to thread t2.

That's not a very useful way to think about threads. You generally don't want a thread in your program to wait for its turn to work on some task: You want it to wait for a task of its own. There will always be some need for threads to coordinate and communicate with each other, but the more you are able to let each thread go off to do its own thing, the better use you will make of them.

Rather than think of "transferring control" from one thread to another, you want each thread to be in control of its own thing, all the time.

How do we notify a second thread which is waiting for a [...] lock?

There is nothing that can release a thread from waiting to enter a synchronized block. That's one of the limitations of synchronized, and that's one of the reasons why it's a bad idea for any thread to ever stay in a synchronized block for any longer than it takes to update a few fields.

I want to make it stop the execution

The simplest way to get the attention of a looping thread is to have the thread check the value of a volatile boolean variable each time around the loop.

volatile boolean timeToStop = false;

MyType myMethod(...) {
    while (! timeToStop) {
        ...
    }
}

Then, any other thread can set timeToStop=true; in order to get the first thread's attention.

Solomon Slow
  • 25,130
  • 5
  • 37
  • 57
1

From your comment:

There is one thread (t2)waiting on a class level lock held by another thread (t1). So is it possible for t1 thread to notify thread t2 before t1 exits from the static synchronized method.

Yes, classes are objects, just call notify().

class Test
{

   synchronized static void printTest( int n )
   {
      for( int i = 1; i <= 10; i++ ) {
         System.out.println( n * i );
      }
      try {
        Test.class.notify();     // just use a class literal
      } catch( Exception ignored ) {
      }

   }
}
markspace
  • 10,621
  • 3
  • 25
  • 39
  • So, we can use wait() and notify() on class level as well right? – A MJ Jul 14 '21 at 05:14
  • 1
    I'm not sure about the terminology "class level" but yes, classes like a literal (`ClassName.class`) or returned by `getClass()` are just object and the methods `notify()` and `wait()` are available just like any other object. – markspace Jul 15 '21 at 04:50