Java-同步块不工作

Java-同步块不工作,java,multithreading,synchronization,Java,Multithreading,Synchronization,我有以下课程 public class OddPrinter implements Runnable { public void run() { try { for (int n = 0; n <= 10; n++) { if((n%2) != 0) System.out.println(" Odd Thread" + n); Threa

我有以下课程

public class OddPrinter implements Runnable  {
    public void run() {
        try {
            for (int n = 0; n <= 10; n++) {
                if((n%2) != 0)
                    System.out.println(" Odd Thread" + n);
                Thread.sleep(1000);
            }
            System.out.println("Exiting Odd Thread");
        }
        catch(InterruptedException e)
        {
            e.printStackTrace();
        }
    }
}
我得到如下输出

Odd Thread1
Odd Thread1
Odd Thread3
Odd Thread3
Odd Thread5
Odd Thread5
Odd Thread7
Odd Thread7
Odd Thread9
Odd Thread9
Exiting Odd Thread
Exiting Odd Thread
同步块可确保 对作为对象成员的方法的调用仅在当前线程完成后发生 已成功输入对象的监视器

根据上面的参考Java2-完整参考-Herbert Schildt,我期望有一个输出,其中一个线程等待另一个线程完成奇数的打印。但事实并非如此。这里的问题是什么

同步块确保只有在当前线程成功进入对象的监视器后,才会调用作为对象成员的方法

不,没有。它确保作为对象类的实例成员的同步方法仅在当前线程退出块(如果在同一对象上调用)后发生,并且在该块退出之前,不会执行同一对象上的另一个同步块


其中一些条件不适用于您的代码。

同步锁应该放在可运行代码中,而不是放在主方法中。 我想你可以把同步放在你的方法上

public class OddPrinter implements Runnable  {
    public synchronized void run() {
        try {
            for (int n = 0; n <= 10; n++) {
                if((n%2) != 0)
                    System.out.println(" Odd Thread" + n);
                Thread.sleep(1000);
            }
            System.out.println("Exiting Odd Thread");
        }
        catch(InterruptedException e)
        {
            e.printStackTrace();
        }
    }
}
或者,你可以这样把它放在你的方法中

public class OddPrinter implements Runnable  {
    static Object lock;
    public void run() {
      synchronized (lock) {
        try {
            for (int n = 0; n <= 10; n++) {
                if((n%2) != 0)
                    System.out.println(" Odd Thread" + n);
                Thread.sleep(1000);
            }
            System.out.println("Exiting Odd Thread");
        }
        catch(InterruptedException e)
        {
            e.printStackTrace();
        }
      }
    }
}

您只同步了一次访问。其他线程不会在对象上同步,因此不会阻止任何内容。即使两个线程都启动了,main中的代码块也会完成,线程也可以自由运行

此外,在main中使用的同步发生在可能发生冲突的任何其他线程之前,并且主线程首先不需要任何共享状态,因此那里的同步是无用的


学习关键部分、内存障碍和Java的概念。购买并学习Brian Goetz等人的《Java并发性在实践中》一书。

您需要更改OddPrinter,在其中可以放置同步块并使用单个锁进行同步,以便一个线程可以同时进入关键部分。并从main方法中删除同步块

    public class OddPrinter implements Runnable {

        private Object lock;

        public OddPrinter(Object lock) {
            this.lock = lock;
        }

        public void run() {

            synchronized (lock) {
                for (int n = 0; n <= 10; n++) {
                    if ((n % 2) != 0)
                        System.out.println(" Odd Thread" + n);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                System.out.println("Exiting Odd Thread");
            }

        }
    }

public class MultiThread {
    public static void main(String[] args) {
        Thread t1, t2;
        Object object=new Object();        

            t1 =new Thread(new OddPrinter(object),"firstThread");
            t1.start();

            t2 =new Thread(new OddPrinter(object),"secondThread"); 
            t2.start();

    }       
}

这绝对不是实现同步的方式。在您的实现中没有监视器/锁或通知实现,因为获取的锁很快就超出了主线程的控制范围

这样做是完全错误的。如果你想做一些独占的事情,锁应该被锁定在你的线程内部,而不是外部

public class MyThread implements Runnable {

 private Object mutex;
 public MyThread(Object sharedObject) {
     this.mutex = sharedObject;
 }

 public void run() {

    // Method 1 -- Class reference used as the  mutex: locks and executes only one instance between the blocks
    synchronized (MyThread.class) {
    }

   // Method 2 -- All the same instance of the object reference used as mutex receives a blocked interference, and only one thread is executed.
   synchronized (mutex) {
   }
 }

 // Method 3 - Only one synchronized method inside the class is executed at any given point in time.
 private synchronized void produce() {
 }

 // Method 3 (Contd.) - Added in conjunction with produce() call
 private synchronized void consume() {
 }
}
我期待一个输出,其中一个线程等待另一个线程完成奇数的打印

在启动线程t2之前,等待线程t1完成:


一个主线程只能访问一个同步块。为什么会有线程在等待另一个呢?线程t1和t2都在同时首先访问对象。两者都在输入对象的run方法。如何允许他们两个都获得first的监视器?不,同步根本不是这样工作的。您可能还想做更多的工作。您引用了一个“参考”,但没有引用它。您可能引用错误,或者它不完整或不正确。@EJP编辑了questionpublic同步类?我理解。但是,根据完整的参考同步块,当您无法访问手头的方法代码时,它可以帮助您实现同步。在这种情况下,假设我没有访问OddPrinter类的源代码。如果我仍然想要实现同步,我能做什么呢?请注意,InterruptedException没有得到处理,更不用说正确处理了,大概是为了简化代码示例。不要让这里显示的随意的习惯用法潜入生产代码中。@Erdnase我想@EJP解释了原因。我对同步块的理解并不是说块中的所有内容都将同步运行。对于您的情况,我猜您需要等待第一个线程完成,然后运行第二个线程。如果是这种情况,您应该在调用t2.start之前调用t1.join。
public class MyThread implements Runnable {

 private Object mutex;
 public MyThread(Object sharedObject) {
     this.mutex = sharedObject;
 }

 public void run() {

    // Method 1 -- Class reference used as the  mutex: locks and executes only one instance between the blocks
    synchronized (MyThread.class) {
    }

   // Method 2 -- All the same instance of the object reference used as mutex receives a blocked interference, and only one thread is executed.
   synchronized (mutex) {
   }
 }

 // Method 3 - Only one synchronized method inside the class is executed at any given point in time.
 private synchronized void produce() {
 }

 // Method 3 (Contd.) - Added in conjunction with produce() call
 private synchronized void consume() {
 }
}
t1.start():
t1.join();
t2.start();