簡體   English   中英

如果一個同步方法調用另一個非同步方法,非同步方法是否有鎖

[英]If a synchronized method calls another non-synchronized method, is there a lock on the non-synchronized method

在 Java 中,如果同步方法包含對非同步方法的調用,那么另一個方法是否仍然可以同時訪問非同步方法? 基本上我要問的是同步方法中的所有內容都對其進行了鎖定(包括對其他同步方法的調用)?

如果一個同步方法調用另一個非同步方法,非同步方法是否有鎖

答案取決於上下文。

如果你是在一個synchronized的對象的方法,然后通過其他線程對同一個對象實例也在其他方法調用synchronized被鎖定。 然而,其他線程對非同步方法的調用不會被鎖定——任何人都可以同時調用它們。

public synchronized void someSynchronizedMethod() {
    ...
    someNonSynchronizedMethod();
    ...
}

// anyone can call this method even if the someSynchronizedMethod() method has
// been called and the lock has been locked
public void someNonSynchronizedMethod() {
   ...
}

此外,如果您調用someSynchronizedMethod()但碰巧在someNonSynchronizedMethod()方法中,您仍然持有鎖。 當您進入同步方法(或塊)時該鎖被啟用,而當您退出該方法時該鎖被禁用。 您可以調用各種其他未同步的方法,它們仍將被鎖定。

但是你在你的問題中問了兩件不同的事情:

在 Java 中,如果同步方法包含對非同步方法的調用,那么另一個方法是否仍然可以同時訪問非同步方法?

是的。 其他方法可以訪問非同步方法。

基本上我要問的是同步方法中的所有內容都對其進行了鎖定(包括對其他同步方法的調用)?

嗯,是的。 其他對同步方法的調用被鎖定。 但是非同步方法不會被鎖定。

另外,請記住,如果該方法是static那么鎖位於ClassLoaderClass對象上。

// this locks on the Class object in the ClassLoader
public static synchronized void someStaticMethod() {

如果方法是一個實例方法,那么鎖就在類的實例上。

// this locks on the instance object that contains the method
public synchronized void someInstanceMethod() {

在這兩種情況下有兩種不同的鎖。

最后,當您處理synchronized實例方法時,類的每個實例都是被鎖定的。 這意味着兩個線程可以同時使用不同的實例在同一個synchronized方法中。 但是如果 2 個線程嘗試在同一個實例上操作synchronized方法,一個線程將阻塞,直到另一個線程退出該方法。

如果線程 A 調用同步方法 M1,而后者又調用非同步方法 M2,則線程 B 仍然可以調用 M2 而不會阻塞。

同步方法在調用它的對象上獲取和釋放內在鎖。 這就是它可能阻塞的原因。 非同步方法不會嘗試獲取任何鎖(除非它在代碼中明確完成)。

因此,如果您還需要確保 M2 的互斥,則無論其調用者(如 M1)是否同步,都應使其同步。

鎖不屬於線程。 鎖實際上屬於對象(或類級別鎖的類),線程在同步上下文中獲取對象(或類級別鎖的情況下的類)上的鎖。 現在,正如上面討論的那樣,java 中沒有鎖傳播。 這是一個小演示:

public class TestThread {

    /**
     * @param args
     * @throws InterruptedException 
     */
    public static void main(String[] args) throws InterruptedException {
        // TODO Auto-generated method stub
        ThreadCreator1 threadCreator1 = new ThreadCreator1();
        ThreadCreator2 threadCreator2 = new ThreadCreator2();

        Thread t1 = new Thread(threadCreator1,"Thread 1");
        Thread t3 = new Thread(threadCreator1,"Thread 3");
        Thread t2 = new Thread(threadCreator2,"Thread 2");

        t1.start();
        Thread.sleep(2000);
        t3.start();

    }
}
public class ThreadCreator1 implements Runnable {

    private static final Task task= new Task();
    private static final Task2 task2= new Task2();

    @Override

    public void run() {

        try {

            if(Thread.currentThread().getName().equals("Thread 1"))
                task.startTask2(task2);
            if(Thread.currentThread().getName().equals("Thread 3"))
                task2.startTask();

        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        // TODO Auto-generated method stub

        /**/

        }
    }

public class Task {

    public static final Task task = new Task();
    public static List<String> dataList = new ArrayList<String>();
    ReentrantLock lock =  new ReentrantLock();



    public  void startTask2(Task2 task2) throws InterruptedException
    {

        try{

            lock.lock();
            //new Task2().startTask();
            task2.startTask();
        }
        catch(Exception e)
        {

        }
        finally{
            lock.unlock();
        }
    }

}
public class Task2 {

    ReentrantLock lock = new ReentrantLock();
    public  void startTask() throws InterruptedException
    {

        try{
            //lock.lock();
            for(int i =0 ;i< 10;i++)
        {
            System.out.println(" *** Printing i:"+i+" for:"+Thread.currentThread().getName());
            Thread.sleep(1000);
        }
        }
        catch(Exception e)
        {

        }
        /*finally
        {
            lock.unlock();
        }*/
    }

}

只是我在這里使用了可重入鎖。 如果上面的代碼運行,那么線程1和線程3之間會有交錯,但是如果Task2類的鎖部分沒有被注釋掉,那么就不會有交錯,先獲取鎖的線程會先完全完成,然后它將釋放鎖,然后另一個線程可以繼續。

鎖屬於線程,而不屬於方法(或更准確地說,屬於它的堆棧框架)。 碰巧的是,如果你有一個同步方法,你可以保證線程在方法體開始之前擁有鎖,然后將釋放它。

另一個線程仍然可以調用第二個非同步方法。 任何線程都可以隨時調用未同步的方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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