2021/04/19

[筆記] Effective Java #79 避免過度同步

Effective Java 3rd 簡體中文版筆記 #79 避免過度同步
上一條討論缺少同步的危險性,本條將討論過度同步可能會導致效能降低、deadlock 及不確定性。在使用同步 (synchronized) 的方法中,不應該調用可以被 @override 的方法或是其他由客戶端傳入的方法,因為無法確定會對同步方法造成什麼影響。

下面程式碼讓客戶端可以實作 hello 方法,當調用 greeting 方法時,會執行客戶端實作的 hello。但客戶端實作時,無意間調用 bye 方法,導致 main 執行後發生 deadlock。
public class Example {   
    static class Friend {
        private final String name;
        private BiConsumer<Friend, Friend> hello;
        public Friend(String name, BiConsumer<Friend, Friend> hello) {
            this.name = name;
            this.hello = hello;
        }
        public String getName() {
            return this.name;
        }

        public synchronized void greeting(Friend friend) {
            hello.accept(this, friend);
        }
        
        private synchronized void bye(Friend friend) {
            System.out.format("%s: Bye, %s!%n", this.name, friend.getName());
        }
    }

    public static void main(String[] args) {
        Friend alex = new Friend("Alex", (self, friend) -> {
            System.out.format("%s: Hello, %s!%n", self.getName(), friend.getName());
            friend.bye(self);
        });
        Friend bill = new Friend("Bill", (self, friend) -> {
            System.out.format("%s: Hello, %s!%n", self.getName(), friend.getName());
            friend.bye(self);
        });
        new Thread(() -> alex.greeting(bill)).start();
        new Thread(() -> bill.greeting(alex)).start();
    }
}
詳細範例
https://docs.oracle.com/javase/tutorial/essential/concurrency/deadlock.html

一般來說,在同步區域內應盡量減少其工作。如果是一個 mutable class,有兩種方法,一為省略所有同步,如果想要允許併發使用,就讓客戶端從外部同步,二是利用內部來同步。在 java.util 中的集合大部分使用前者,在 java.util.concurrent 中採用後者。

轉載請註明原文網址 https://cookieandcoketw.blogspot.com/2021/04/effective-java-79-excessive-synchronization.html

沒有留言:

張貼留言