Java 为什么同步方法不适用于多线程

Java 为什么同步方法不适用于多线程,java,multithreading,synchronized,Java,Multithreading,Synchronized,我写了一个程序,其中两个线程正在运行,这就是为什么我使用synchronized关键字。我的代码在下面- public class TestThreadAnother { public synchronized void decrement(){ try { for (int i = 4; i > 0; i--) { System.out.println("Thread " + i);

我写了一个程序,其中两个线程正在运行,这就是为什么我使用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专家需要您帮助解决此问题。

输出正确。只有
减量()
方法是同步的。这意味着此对象的
decrement()
方法一次不能被多个线程调用。但这并不能阻止其他线程在一个线程执行减量()时执行其他操作


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

@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();
    }
}

你必须明白的重要一点是<代码>同步仅保证两个线程不会同时持有同一对象上的锁。在您的情况下,一个线程(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

在减量方法中打印
线程.getName()
,以获得更好的效果。

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

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);

}   

因为“Running…”和“End of Running…”的
System.out.println
decrement()
方法不在原子操作中

如果要继续使用同步方法,请执行以下操作:

把钥匙放好

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


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

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


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

您可以在第一个线程上使用以下命令从外部处理此问题:

t1.start(); // Start t1
t1.join();  // Wait for t1 to complete
t2.start(); // Start t2
如果需要主线程在线程一次运行一个线程时保持执行,可以创建一个管理器线程来执行它们。幸运的是,已经有人:

创建一个执行器,该执行器使用单个工作线程在无界线程上运行 队列(但是请注意,如果此单个线程由于 在关机前执行过程中出现故障,将使用新的 如果需要执行后续任务,请放置。)保证按顺序执行任务,并且在任何给定时间都不会有多个任务处于活动状态。


(emphasis mine)

只有在thread2完成减量方法后,thread1才执行相同的方法-因为只有该方法是同步的
decrement()
中的try/catch()会捕获什么?但是如果我希望我的输出与第一个一样,那么我应该怎么做?你会将两个系统放入.out.println()在decrement()方法中调用run()方法。或者在两个线程之间共享一个Runnable,并同步其run()方法。或者在共享锁对象上显式同步run()方法的整个主体。但这仍然不能保证线程1在线程2之前启动。@user3732316请按照我在回答中提到的方式尝试。仍然不能保证线程1先执行线程2,因为有时我会得到-创建线程1创建线程2运行线程2线程4线程3线程2线程1末端减量:线程2运行线程1线程4线程3线程2线程1末端减量:线程1是的,这永远不能保证。线程调度程序可以首先从线程池中自由选择任何可运行的线程。如果您想先执行线程t1,您可能必须在启动线程t1后放置thread.sleep。如果我同步了obj1,那么仍然不能确定每次线程1都会先执行,然后执行线程2。因为在o/p中,有时线程1先执行,然后执行线程2,有时反之亦然。@user3732316-是。。你是对的。。没有保证。你能做的就是使用
thread\join
t1.start(); // Start t1
t1.join();  // Wait for t1 to complete
t2.start(); // Start t2
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(t1);
executor.execute(t2);