[英]Can two threads run two different methods at the same point of time?
class A {
private synchronized f() {
...
...
}
private void g() {
...
...
}
}
如果线程T1正在运行已同步的f(),那么线程T2是否可以在T1仍在运行f()的同时运行未在同一时间同步的g()?
不在同一A实例上。该实例本身是锁,因此如果两个线程同时使用两个线程执行两个方法,则需要两个A实例。
是。 两种方法都可以在同一实例上同时执行。
仅f()
被同步。 线程必须获取此this.f()
的监视器才能执行f()
并且每个实例仅存在一个监视器。
g()
不同步,不需要监视器锁定即可运行该方法,因此任何线程都可以随时执行g()
。
“同步方法在执行之前先获取一个监视器(第17.1节)。”
http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.4.3.6
不会。一个呼叫将阻塞,直到另一个呼叫结束。 这样做的原因是方法上的synced关键字扩展为在对象的当前实例上进行同步。 更具体地说,请考虑以下代码:
private void synchronized f() { ... }
上面的代码在功能上与以下代码相同:
private void f() { synchronized (this) { ... } }
因此,如果您希望对象中的两个方法仅彼此同步,则应创建两个锁对象。 每个方法都应将其所有代码包装在一个同步的(对象)块中,每个方法一个对象。
是的,如果T1和T2在A的不同实例上分别执行f
和g
。
如果两个线程都在A的同一实例上执行一个方法,则一次只能执行一个方法。 如果T1首先运行,它将获取A实例的锁,并执行方法f
。 线程T2将无法执行方法g
直到T1完成执行f
。 否则可能会发生相反的情况:T2可以先运行g
,而T1将在T2完成后才能运行f
。
正确的答案是重组者的答案。
运行此命令,您将看到。 您还可以通过取消注释/注释样本的相应部分来使用Thread.sleep()而不是无限循环进行测试。
如果代码没有遵循最佳实践,我深表歉意,我的Java很生锈。
package threadtest;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ThreadTest {
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws IOException {
TestClass tc = new TestClass();
// invokes not sync method
FirstThreadRunnable ftr = new FirstThreadRunnable(tc);
Thread t1 = new Thread(ftr);
// invokes the sync method
SecondThreadRunnable str = new SecondThreadRunnable(tc);
Thread t2 = new Thread(str);
t2.start();
t1.start();
System.in.read();
}
public static class TestClass {
private int callCount = 0;
public void notSynchronizedMethod() {
System.out.println("notSynchronizedMethod says hello!" + " [" + callCount++ +"] from thread: " + Thread.currentThread().getId());
}
public synchronized void synchronizedMethod() throws InterruptedException {
// Test with the sleep
//System.out.println("entering sync method and pausing from thread: " + Thread.currentThread().getId());
//Thread.sleep(5000); // hold the monitor for 5sec
//System.out.println("exiting sync method" + " [" + callCount++ +"] from thread: " + Thread.currentThread().getId());
// Test with spinning
System.out.println("MAKE IT SPIN! from thread: " + Thread.currentThread().getId());
boolean spin = true;
while(spin){
}
System.out.println("IT STOPPED SPINNING! from thread: " + Thread.currentThread().getId());
}
}
// invokes the not sync method
public static class FirstThreadRunnable implements Runnable {
TestClass tester = null;
public FirstThreadRunnable(TestClass tester){
this.tester = tester;
}
@Override
public void run() {
for(int i = 0; i < 500; i++){
tester.notSynchronizedMethod();
try {
Thread.sleep(50);
} catch (InterruptedException ex) {
Logger.getLogger(ThreadTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
// invokes the sync method
public static class SecondThreadRunnable implements Runnable {
TestClass tester = null;
public SecondThreadRunnable(TestClass tester){
this.tester = tester;
}
@Override
public void run() {
try {
// Test with Sleep()
//for(int i = 0; i < 5; i++){
// tester.synchronizedMethod();
//}
// Test with the spinning
tester.synchronizedMethod();
} catch (InterruptedException ex) {
Logger.getLogger(ThreadTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
通常,两个线程可以在同一时间运行两个方法。 但是,在您的示例中,在任何给定时刻,只有一个线程可能正在运行f()
或g()
。
使用synchronized
关键字更改线程交互。 每个java对象都有一个锁,这是一个在任何给定时间只能拥有一个线程的项。 Synchronized
是一个命令,它指导线程在执行方法之前获取锁,然后在释放锁。 在整个方法执行过程中将保持锁定。
在您的示例中,在任何给定时间,只有一个线程将执行f()
或g()
,因为“其他”线程将等待其轮换来抓住锁。
当您具有两个相同类的对象时,您将拥有两个锁。 这意味着您可以让两个线程同时运行f()
和g()
,并且完整保留synchronized
关键字,因为这些线程将在不同对象上获取锁。 如果不删除synchronized
关键字,就无法使线程在同一对象上同时执行。
对于技术性和pedanticality的利益, 是的 ,这两种方法可以在同一时间进入。 至少在同步(此)上被阻止,但进入方法并正在运行,它的第一条语句正在执行,并且第一条字节码指令已执行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.