class A {
private synchronized f() {
...
...
}
private void g() {
...
...
}
}
如果线程T1正在运行同步的f(),那么线程t2可以运行g(),它在同一时间点不同步,而T1仍在运行f()吗?
答案 0 :(得分:16)
不在同一个A实例上。实例本身就是锁,所以两个方法同时执行两个方法,两个线程需要两个A实例。
答案 1 :(得分:6)
是。两种方法都可以在同一个实例上同时执行。
仅同步f()
。线程必须获取this.f()
的监视器才能执行f()
,并且每个实例只存在一个监视器。
g()
未同步,运行该方法不需要监视器锁定,因此任何线程都可以随时执行g()
。
“同步方法在执行之前获取监视器(第17.1节)。”
http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.4.3.6
答案 2 :(得分:4)
没有。一个呼叫将阻塞,直到另一个完成。原因是方法上的synchronized关键字扩展为在对象的当前实例上同步。更具体地说,请考虑以下代码:
private void synchronized f() { ... }
以上代码的功能与以下代码相同:
private void f() { synchronized (this) { ... } }
因此,如果您希望对象中的两个方法仅相互同步,则应创建两个锁定对象。每个方法都应将其所有代码包装在同步(对象)块中,每个方法都有一个对象。
答案 3 :(得分:3)
是的,如果T1和T2分别在A的不同实例上执行f
和g
。
如果两个线程在同一个A实例上执行方法,则一次只能执行一个方法。如果T1先运行,它将获取A实例的锁定,并执行方法f
。在T1完成执行g
之前,线程T2将无法执行方法f
。或者相反的情况可能发生:T2可以先运行g
,T1在T2完成之后将无法运行f
。
答案 4 :(得分:2)
通常,两个线程可以在同一时间点运行两个方法;但是,在您的示例中,在任何给定时刻,只有一个线程可能正在运行f()
或g()
。
使用synchronized
关键字更改线程交互。每个java对象都有一个锁,一个只有一个线程可以在任何给定时间保存的项。 Synchronized
是一个命令,它指示线程在执行方法之前获取锁,然后释放它。在整个方法执行期间保持锁定。
在您的示例中,在任何给定时间只有一个线程将执行f()
或g()
,因为“其他”线程将轮流等待获取锁定。
当你有两个同一个类的对象时,你有两个锁。这意味着你可以让两个线程同时运行f()
和g()
synchronized
关键字,因为线程将抓取不同对象的锁。如果不删除synchronized
关键字,您就无法在同一对象上同时执行线程。
答案 5 :(得分:2)
对此的正确答案是重新组装者的答案。
运行这个,你会看到。您还可以通过取消注释/注释样本的相应部分来使用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);
}
}
}
}
答案 6 :(得分:0)
为了技术性和迂腐的兴趣,是,两种方法可以同时输入。一个在synchronized(this)上被阻塞,非常少,方法进入并运行,它的第一个语句正在执行,并且执行了第一个字节代码指令。