为什么synchronized方法不适用于多线程

时间:2014-07-09 06:00:52

标签: java multithreading synchronized

我编写了一个程序,其中运行了两个线程,这就是我使用synchronized关键字的原因。我的代码在下面 -

public class TestThreadAnother {
    public synchronized void decrement(){
        try {
            for (int i = 4; i > 0; i--) {
                System.out.println("Thread " + i);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


public class TestThreadClass extends Thread {
    private String threadName;
    TestThreadAnother obj1;

    public TestThreadClass(String threadName, TestThreadAnother Obj1) {
        this.threadName = threadName;
        obj1 = Obj1;
        System.out.println("Creating " + threadName);
    }

    @Override
    public void run() {
        System.out.println("Running " + threadName);
        obj1.decrement();
        System.out.println("End of " + threadName);
    }    
}

public class TestThreadMain {

    public static void main(String[] args) {
        TestThreadAnother obj1 = new TestThreadAnother();

        TestThreadClass t1 = new TestThreadClass("Thread 1", obj1);
        TestThreadClass t2 = new TestThreadClass("Thread 2", obj1);

        t1.start();
        t2.start();
    }
}

输出应该是 -

Creating Thread 1
Creating Thread 2
Running Thread 1
Thread 4
Thread 3
Thread 2
Thread 1
End of Thread 1
Running Thread 2
Thread 4
Thread 3
Thread 2
Thread 1
End of Thread 2

但我得到以下结果 -

Creating Thread 1
Creating Thread 2
Running Thread 2
Thread 4
Thread 3
Running Thread 1
Thread 2
Thread 1
Thread 4
Thread 3
Thread 2
Thread 1
End of Thread 1
End of Thread 2

但我的问题是因为我使用的是同步方法然后为什么会发生这种情况?因为知道我是否使用synchronized,所以在第一个线程将执行然后第二个将执行。但在我的情况下,有时这不会发生。 Java专家需要您就此问题提供帮助。

6 个答案:

答案 0 :(得分:11)

输出正确。仅同步您的decrement()方法。这意味着此对象的decrement()方法一次不能被多个线程调用。但是,当一个线程执行decrement()时,这并不妨碍其他线程做其他事情。

您的输出显示当线程2正在执行decrement()时,线程1正在执行System.out.println()方法中的第一个run(),然后可能等待线程2完成其调用decrement(),然后执行decrement()

答案 1 :(得分:5)

您必须了解的重要事项是。 Synchronization仅保证两个线程不会同时锁定同一对象。在您的情况下,一个线程(thread2或thread1)将获得锁定并将调用decrement()方法。直到此线程结束,其他threda将被阻止。

现在,分析你的输出:

Creating Thread 1
Creating Thread 2
Running Thread 2 // Thread -2 has the lock now.
Thread 4         // thrad-2's decrement()
Thread 3
Running Thread 1  // thread-1 is blocked. So, only this line is printed
Thread 2         // still thread2
Thread 1      // still thread2
Thread 4        // now thread1 decrement() starts
Thread 3
Thread 2
Thread 1
End of Thread 1
End of Thread 2

在你的减量方法中打印thread.getName()以获得更好的想法。

答案 2 :(得分:3)

你应该这样做,

@Override
public void run() {
    synchronized(obj1){
          System.out.println("Running " + threadName);
          obj1.decrement();
          System.out.println("End of " + threadName);
    }

}    

方法可以是非同步的

public void decrement(){
    try {
        for (int i = 4; i > 0; i--) {
            System.out.println("Thread " + i);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

答案 3 :(得分:2)

这是因为以下两行不在同步块中:

System.out.println("Running " + threadName);

System.out.println("End of " + threadName);

所以在递减之前和之后()可以切换线程。如果您想要预期的观察,您可以修改如下的减量方法:

public synchronized void decrement(String threadName ){
        System.out.println("Decrement: " + threadName);
        try {
            for (int i = 4; i > 0; i--) {

                System.out.println("Thread " + i);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("End Decrement: " + threadName);
    }

更改下面的运行方法,

public void run() {
    obj1.decrement(threadName);

}   

答案 4 :(得分:2)

其他答案已经解释了为什么synchronized没有按预期工作。这更像是评论的后续行动:

  

仍然不能保证我的线程1先执行然后再执行2

你可以在第一个使用join来处理线程的外部:

t1.start(); // Start t1
t1.join();  // Wait for t1 to complete
t2.start(); // Start t2

如果您需要主线程继续执行,而线程一次运行一个,您可以创建一个管理器线程来执行它们。幸运的是,已有人did this for us

ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(t1);
executor.execute(t2);
  

public static ExecutorService newSingleThreadExecutor()

     

创建一个使用单个工作线程执行无限制的执行程序   队列。 (但请注意,如果此单个线程由于a而终止   在关机之前执行失败,一个新的将采取它   如果需要执行后续任务,则放置。)保证任务按顺序执行,并且在任何给定时间不会有多个任务处于活动状态。

(强调我的)

答案 5 :(得分:0)

从“运行...”和“运行结束......”System.out.println以及decrement()方法不在原子操作中

如果你想坚持使用同步方法:

只需输入

System.out.println("Running " + threadName); 

System.out.println("End of " + threadName);

decrement()方法中,我认为您将能够获得所需的输出。