[英]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.