Thread.sleep 也在阻塞其他线程,处理其他方法,以及在同步方法中调用的自身

Thread.sleep is blocking other thread also, working on other method, along with itself callled inside synchronized method

class Common
{

public synchronized void synchronizedMethod1() 
    {
        System.out.println("synchronized Method1 called");
        try
        {
        Thread.sleep(1000);
        } 
        catch (InterruptedException e) 
        {
        e.printStackTrace();
        }
        System.out.println("synchronized Method1 done");
    }

public synchronized void synchronizedMethod2() 
{
    System.out.println("synchronized Method2 called");
    try
    {
    Thread.sleep(1000);
    }
    catch (InterruptedException e) 
    {
    e.printStackTrace();
    }
    System.out.println("synchronized Method2 done");
}
}

在上面的 class 中,我有两个同步方法,它们是从另一个 class 的 运行 方法调用的。其他class代码如下:

public class ThreadClass implements Runnable
{
    private int id = 0;
    private Common common;

public ThreadClass(int no, Common object)
{
    common = object;
    id = no;
}

public void run()
{
    System.out.println("Running Thread " + Thread.currentThread().getName());
    try 
    {
        if (id == 11) 
        {
            common.synchronizedMethod1();
        } 
        else
        {
            common.synchronizedMethod2();
        }
    } 
    catch (Exception e)
    {
        e.printStackTrace();
    }
}

public static void main(String[] args)
{
    Common c = new Common();
    ThreadClass tc = new ThreadClass(11, c);
    ThreadClass tc1 = new ThreadClass(20, c);
    Thread t1 = new Thread(tc, "Thread 1");
    Thread t2 = new Thread(tc1, "Thread 2");
    t1.start();
    t2.start();
}
}

我从 main 方法启动了两个不同的线程。在 运行 方法中,我给出了将两个不同线程发送到不同同步方法的条件。代码产生的输出是:

Running Thread Thread 2
Running Thread Thread 1
synchronized Method2 called
synchronized Method2 done
synchronized Method1 called
synchronized Method1 done

我对输出的问题是: 当线程 2 转到同步方法 2 时,它打印第 3 行输出并进入休眠状态 1 秒。现在,由于线程 1 没有被任何东西阻塞,所以它应该在输出的第 3 行之后执行并打印输出的第 5 行,然后应该进入睡眠状态,但是当线程 2 进入睡眠状态时,这并没有发生,它使线程 1 也进入睡眠状态然后第一个线程 2 完成它的执行,然后线程 1 完成它的执行。

如果我从方法中删除 synchronized 关键字,则不会发生这种行为。 您能否解释一下使用和不使用同步关键字处理代码的不同方式背后的原因。

提前致谢。

休眠线程不会释放其锁,但您可以将 sleep(...) 调用替换为 wait(...)。但请记住,只有调用了 wait(...) 的对象的锁才会被释放,因此如果您希望在等待时释放多个锁,则必须设计不同的解决方案。

首先synchronized关键字用来定义互斥。这里的互斥是通过Monitor的概念来实现的。还有一件事是 sleep 不释放监视器。它只是暂停当前线程的执行一段时间。其他需要监视器的线程必须等到获得监视器的线程释放它。

有两种使用方式synchronized...

第一个是使用同步块。

synchronized(obj){...}

这里如果任何线程想要进入同步块,它必须获得对象的监视器。

第二个是使用同步方法。

synchronized void meth(){...}

同步方法和块之间的主要区别是同步方法使用对象监视器它自己和同步块可以有任何对象的监视器

同步方法可以使用同步块定义如下...

void meth(){
    synchronized (this){
        //method body
    }
}

现在你可以使用synchronized块来防止阻塞另一个方法的问题。这里你必须在不同的对象上定义同步块,这样两个方法可以并发执行,但多个线程不能同时执行同一个方法。

同步一个方法并不仅仅意味着同步方法本身

synchronized void x(){}

等于:

 void x(){ 
  synchronised(this){}
 }

由于两个线程访问相同 Common 实例第一个线程将获得 Common 对象锁的所有权,这与调用哪个同步方法无关,它只会在该方法主体完成其工作后释放该锁。 如果您要发送两个 Common 实例,则不会有问题,因为它们不是静态的。另外,您可能对 ReentrantLock

感兴趣

Such a behavior is not happening if I remove synchronized keyword from methods. Can you please explain me the reason behind different way of processing the code with and without synchronized keywords.

这实际上就是 synchronized 关键字的全部目的。当您有多个相同 class 的同步实例方法时,一次只能执行一个。你写了这个:

class Common {
    public synchronized void synchronizedMethod1(){}
    public synchronized void synchronizedMethod2(){}
}

因为两个方法是同步的,一次只能执行一个。其中一个无法启动另一个已完成。

这是如何工作的?简而言之,您有一个 Common 对象并调用它的同步实例方法。当您调用 synchronzedMethod1 时,该方法将 "lock" Common 对象(称为 "acquiring the lock")。虽然该方法在那个 Common 对象上有那个锁,但如果您尝试在同一对象上调用任何其他同步方法,它会尝试锁定它并且会发现它已经被锁定。因此,任何其他锁定该对象的尝试都将挂起,直到他们可以这样做为止。 synchronizedMethod1 完成后,它将解锁 Common 对象(称为 "releasing the lock"),然后任何人都可以尝试锁定它,例如 synchronzedMethod2

所以简而言之,synchronized 专门制作了它,所以您不能同时发生相同 class 的两个同步方法。这很有用,因为不这样做可能会导致一些有问题的行为。例如,ArrayList 不会这样做,所以如果一个线程试图将一个对象添加到 ArrayList 而另一个线程试图迭代它,它可能会抛出一个 ConcurrentModificationException 并使每个人伤心。