Java 为什么同步方法不适用于多线程
我写了一个程序,其中两个线程正在运行,这就是为什么我使用synchronized关键字。我的代码在下面-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);
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);