簡體   English   中英

兩個線程可以在同一時間運行兩種不同的方法嗎?

[英]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的不同實例上分別執行fg

如果兩個線程都在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM