多线程同步

时间:2015-08-07 09:46:22

标签: java multithreading

同步与以下代码配合良好。

  public class Main implements Runnable {
    public static void main(String[] args) {
        Main m = new Main();
        for (int i = 0; i < 2; i++) {
            Thread t = new Thread(m);
            t.start();
        }
    }

    @Override
    public void run() {
        synchronized(this) {
            for (int i = 0; i < 500; i++) {
                System.out.println(i);
            }
        }
    }
 }

 // Synchronization isn't working here.

 public class Main implements Runnable {
    public static void main(String[] args) {
        for (int i = 0; i < 2; i++) {
            Thread t = new Thread(new Main());
            t.start();
        }
    }

    @Override
    public void run() {
        synchronized(this) {
            for (int i = 0; i < 500; i++) {
                System.out.println(i);
            }
        }
    }
 }

在一次采访中询问了这个问题。我对此有点困惑,所以我试图理解为什么同步不能与第二个代码片段一起使用。任何人都可以解释为什么同步不能与第二个代码片段一起使用吗?

6 个答案:

答案 0 :(得分:6)

因为如果您正在处理单个对象,则应用同步。

在第一种情况下,您有一个Main的单个可运行对象,即m

在第二种情况下,您拥有Main的独立对象。

for(int i=0;i<2;i++){
    Thread t = new Thread(new Main()); // independent objects for each thread
    t.start();
}

<强>阐释:

如果您在代码

下面看到代码
synchronized (this) {

this指的是对象本身。因此,基于此对象应用锁定。因此,在多个Main类对象的情况下,它们独立工作,而单一对象同步仅适用于该对象。

有关更多信息,请参阅:Intrinsic Locks and Synchronization

文档中的代码

public class MsLunch {
    private long c1 = 0;
    private long c2 = 0;
    private Object lock1 = new Object();
    private Object lock2 = new Object();

    public void inc1() {
        synchronized(lock1) { // lock is acquired using lock1 object 
            c1++;
        }
    }

    public void inc2() {
        synchronized(lock2) { // lock is acquired using lock1 object 
            c2++;
        }
    }
}

在此示例中,您可以同时使用单个对象同时调用方法inc1()inc2(),因为在不同对象上获取了锁。这将有助于您更好地理解它。

因此,在您的情况下,锁定是在this(对象本身)上获取的。因此,只要你有多个对象,它就可以独立工作,当你拥有单个对象时,它将同步工作。

答案 1 :(得分:2)

您在这里创建了两个对象。

如果多个线程试图访问它,

synchronized(this)块将同步对同一对象的访问。

答案 2 :(得分:1)

 synchronized (this)

“this”是当前的对象实例。在第一个示例中,在调用线程之前创建Main类的实例,并使用相同的实例。因此同步工作。 但是在第二个例子中,在main()循环的每次迭代中,都创建了Main的新实例。 synchronized(this)将无法工作,因为Main类有多个实例。

答案 3 :(得分:1)

Java syncronized(object)中的

实际上使用object作为syncronized内代码块的排他锁。如果我们将锁显式化,并观察在每种情况下创建了多少锁的实例,为什么第二个版本不起作用可能更为明显:

 public class Lock {
 }

 public class Main(Lock lock) implements Runnable {
    public static void main(String[] args) {
        correct()
        incorrect()
    }

    public static void incorrect() {
      for (int i = 0; i < 2; i++) {
            //New lock created each iteration
            Main m = new Main(new Lock())
            Thread t = new Thread(m);
            t.start();
        }
    }

     public static void correct() {
     //One lock used for all iterations
      Main m = new Main(new Lock())
      for (int i = 0; i < 2; i++) { 
            Thread t = new Thread(m);
            t.start();
        }
    }

    @Override
    public void run() {
        synchronized(lock) {
            for (int i = 0; i < 500; i++) {
                System.out.println(i);
            }
        }
    }
 }

答案 4 :(得分:1)

// Synchronization isn't working here.

 public class Main implements Runnable {
    public static void main(String[] args) {
        for (int i = 0; i < 2; i++) {
            Thread t = new Thread(new Main());
            t.start();
        }
    }

    @Override
    public void run() {
        synchronized(this) {
            for (int i = 0; i < 500; i++) {
                System.out.println(i);
            }
        }
    }
 }

在上面的示例中,有3个线程和3个Main对象,每个线程对不同的Main对象进行锁定,因此同步不起作用。为了使同步工作,我们应该让所有线程锁定单个对象。这里有3个线程没有锁定单个对象,而是3个不同的对象。每个线程都锁定每个主要对象,这些主要对象不在线程之间共享。在Thread t = new Thread(m);所有线程都锁定单个Main(m)对象。

答案 5 :(得分:0)

我会用自己的问题回答这个问题:

你是什么意思,它没有工作

第一个示例序列化了System.out.println()个调用,并且由于此处其他几个答案中给出的原因,第二个示例并未对这些调用进行序列化,但那又是什么?

System.outjava.io.PrintWriterPrintWriter本质上是线程安全的。这两个示例都不需要同步。