1

我对同步块有疑问。执行以下代码后,即时输出为:

Inside run=>thread 2
Inside run=>thread 1
Inside run=>thread 1
Inside run=>thread 2
Inside run=>thread 2
Inside run=>thread 1
Inside run=>thread 2
Inside run=>thread 1
Inside run=>thread 1
Inside run=>thread 2

我期待输出,因为只有一个线程将首先执行同步块,然后只有第二个线程将访问同步块。可能我对这个概念的理解有误吗?

 package com.blt;

    public class ThreadExample implements Runnable {
        public static void main(String args[])
        {


            System.out.println("A");
            Thread T=new Thread(new ThreadExample());
            Thread T1=new Thread(new ThreadExample());
            System.out.println("B");
            T.setName("thread 1");
            T1.setName("thread 2");
            System.out.println("C");
            T.start();
            System.out.println("D");
            T1.start();
        }


     synchronized public void run()
    {
        for(int i=0; i<5; i++)
        {
            try
            {
             System.out.println("Inside run=>"+Thread.currentThread().getName());
             Thread.currentThread().sleep(2000);
            }
             catch(InterruptedException e)
            {
                e.printStackTrace();
            }
          }  
    }
    }
4

5 回答 5

4

您的每个线程都在不同的对象上同步。所以是的,他们不会把对方锁在外面。但更重要的是,该run方法是为没有Runnable同步修饰符的接口定义的,您不应该向它添加一个(正如您已经看到的,它没有达到您认为的效果)。

要记住的关键是,当您在方法上使用同步修饰符时:

public synchronized void someMethod();

它实际上与使用synchronized(this). 在这两种情况下,您都锁定了对象监视器。如果您有多个对象,则您有多个监视器。

这是您自己的示例的修改版本,它将按您的预期工作。它使用一个通用对象监视器(在本例中是您的类本身),以便同步按预期工作:

public class ThreadExample implements Runnable {
    public static void main(String args[]) {
        System.out.println("A");
        Thread T = new Thread(new ThreadExample());
        Thread T1 = new Thread(new ThreadExample());
        System.out.println("B");
        T.setName("thread 1");
        T1.setName("thread 2");
        System.out.println("C");
        T.start();
        System.out.println("D");
        T1.start();
    }

    public void run() {
        synchronized (ThreadExample.class) {
            for (int i = 0; i < 5; i++) {
                try {
                    System.out.println("Inside run=>"
                            + Thread.currentThread().getName());
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
于 2013-02-11T10:15:36.137 回答
3

您的问题是,如果 2 个同步块没有锁定在同一个监视器上,它们就不是互斥的。

请记住,同步方法锁定在this监视器上 - 您的代码相当于:

 public void run() {
    synchronized(this) {
        //your code here
    }
 }

由于您创建了两个实例,ThreadExample它们每个实例都有一个不同的this.

您可以通过在两个线程中使用相同的锁来解决您的问题,例如:

 public void run() {
    synchronized(ThreadExample.class) {
        //your code here
    }
 }

甚至更好,只创建一个QuoiThreadExample指出的实例。

于 2013-02-11T10:17:00.033 回答
1

您已经创建了两个 Object ThreadExample,因此每个线程都有不同的synchronized方法。

创建单个对象并将引用传递给线程,您将看到同步效果。:)

ThreadExample thex = new ThreadExample();
Thread T=new Thread(thex);
Thread T1=new Thread(thex);

这里两个线程都将使用相同的synchronized方法。

于 2013-02-11T10:16:02.093 回答
0

呃,你正在同步每个线程的运行方法。Thread1 不会尝试运行 Thread2 的 run 方法,反之亦然。这就是为什么它实际上与根本不同步的原因相同。

于 2013-02-11T10:17:40.007 回答
0

您正在创建该类的两个实例,并且您正在对类进行同步,因此它们将独立运行,因为没有公共锁。他们将继续单独运行。

于 2013-02-11T10:18:20.520 回答