Java Thread synchronization - Thread.sleep() Metho

2019-01-26 16:44发布

问题:

i heard, sleep() will lock the current sync method/block But here, when i call sleep() on thread 1, thread 2 is able to access the same block? Can anyone Explain?

Main.java

public class Main {     
    public static void main(String args[])
    {
        Thread1 t1 = new Thread1();
        Thread2 t2 = new Thread2();
        System.out.println("going to start t1");
        t1.start();
        System.out.println("going to start t2");
        t2.start();

    }

}

=====================================================================

Thread1.java

public class Thread1 extends Thread{

    public void run() { 
        Syncc s1 = new Syncc();
        s1.me("T1:");
    }   

}

=====================================================================

Thread2.java

public class Thread2 extends Thread{

    public void run() { 
        Syncc s2 = new Syncc();
        s2.me("T2:");
    }   
}

=====================================================================

Syncc.java

public class Syncc{

    public void me(String s){
        synchronized(this){
        for(int i=0; i<=5; i++)
        {
            System.out.println(s+" "+" "+i);
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {              
                e.printStackTrace();
            }
        }
    }
}
}

==========================================

Output:

going to start t1
going to start t2
T2:  0
T1:  0
T2:  1
T1:  1
T1:  2
T2:  2
T1:  3
T2:  3
T1:  4
T2:  4
T2:  5
T1:  5

BUT according to sleep() method, it should not unlock the current synchronization block right? if so the out put should be..

going to start t1 going to start t2

T1:  0
T1:  1
T1:  2
T1:  3
T1:  4
T1:  5
T2:  0
T2:  1
T2:  2
T2:  3
T2:  4
T2:  5

i mean after thread 1 execution only thread 2 should start right? Whats the issue?

回答1:

This is because you have two different instances of Syncc in play here. Each thread has its own copy of Syncc.

Try doing the same with a single instance. You could also synchronize on the static context and try.

To simulate, modify Thread1 and Thread2 to accept an instance of Syncc.

public class Thread1 extends Thread {
    private Syncc syncc;

    public Thread1(Syncc syncc) {
        this.syncc = syncc;
    }

    public void run() { 
        this.syncc.me("T1:");
    }   
}

You can then start them as so:

public static void main(String args[]) {
    Syncc syncc = new Syncc();

    Thread1 t1 = new Thread1(syncc);
    Thread2 t2 = new Thread2(syncc);

    System.out.println("going to start t1");
    t1.start();
    System.out.println("going to start t2");
    t2.start();
}


回答2:

Rules of Sleep, Yield and Join

  • Sleeping is used to delay execution for a period of time, and no locks are released when a thread goes to sleep.

  • A sleeping thread is guaranteed to sleep for at least the time specified in the argument to the sleep() method (unless it's interrupted), but there is no guarantee as to when the newly awakened thread will actually return to running.

  • The sleep() method is a static method that sleeps the currently executing thread's state. One thread cannot tell another thread to sleep.

  • The setPriority() method is used on Thread objects to give threads a priority of between 1 (low) and 10 (high), although priorities are not guaranteed, and not all JVMs recognize 10 distinct priority levels—some levels may be treated as effectively equal.

  • If not explicitly set, a thread's priority will have the same priority as the priority of the thread that created it.

  • The yield() method may cause a running thread to back out if there are runnable threads of the same priority. There is no guarantee that this will happen, and there is no guarantee that when the thread backs out there will be a different thread selected to run. A thread might yield and then immediately reenter the running state.

  • The closest thing to a guarantee is that at any given time, when a thread is running it will usually not have a lower priority than any thread in the runnable state. If a low-priority thread is running when a high-priority thread enters runnable, the JVM will usually preempt the running low-priority thread and put the high-priority thread in.

  • When one thread calls the join() method of another thread, the currently running thread will wait until the thread it joins with has completed. Think of the join() method as saying, "Hey thread, I want to join on to the end of you. Let me know when you're done, so I can enter the runnable state."

http://www.amazon.com/SCJP-Certified-Programmer-Java-310-065/dp/0071591060



回答3:

You have created two Synch objects each object corresponding to one thread . Each object has its own copy of me. Hence when your start each thread, withing the run method the thread is calling its own copy of the function me. Since the two thread act only on their copy this works like a single thread scenario. If you do want to test a multithread scenario then make the method me static(class level method) and apply a class level lock.

Thread1.java

public class Thread1 extends Thread{

public void run() { 
    Syncc.me("T1:");
}   

}

Thread2.java

public class Thread2 extends Thread{

public void run() { 
    Syncc.me("T2:");
}   

}

Syncc.java

public class Syncc{

public static void me(String s){
    synchronized(Syncc.class){
    for(int i=0; i<=5; i++)
    {
        System.out.println(s+" "+" "+i);
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {              
            e.printStackTrace();
        }
    }
}

} }