【java】知識系譜-基礎篇-線程-發佈、逸出

java併發編程實戰的解釋,不夠詳細,尤爲this引用逸出讓人理解有些費解,java併發編程實戰裏面的內容就直接拷貝過來java

發佈:使對象可以在當前做用域以外的代碼中使用
逸出:當某個不應被髮布的對象被髮布時,這種狀況稱爲逸出
發佈內部狀態將會破壞封裝性,並使得程序難以維持不變性條件
當某個對象逸出後,必須對程序進行分析,以便找出哪些對象或線程可能會誤用該對象,這正是使用封裝的最主要緣由:使對程序的正確性分析變爲可能,並使無心中破壞設計約束條件變得更難
不管其它的線程會對逸出的對象引用執行何種操做,都不重要,由於誤用該引用的風險始終是客觀存在的

發佈的實現方式

1.對象引用做爲非私有屬性

代碼示例:編程

//只是代碼示例,不推薦這樣初始化List
public class test {
    public List<Animal> animals = new ArrayList<Animal>(){{
        add(new Animal());
    }};
}

List對象和List中的Animal對象都被髮布出去。併發

2.對象引用被非私有方法返回

代碼示例:函數

//只是代碼示例,不推薦這樣初始化List
public class test {
    private List<Animal> animals = new ArrayList<Animal>(){{
        add(new Animal());
    }};
    
    public List<Animal> getAnimals(){
        return animals;
    }
}

一、2的同樣,List對象和List中的Animal對象發佈出去。只是一個是方法發佈出去,一個是屬性發布出去。this

3.外部方法發佈對象

外部方法定義:
對當前類來講,外部方法是指行爲不徹底由當前類來規定的方法,包括其餘類中定義的方法以及當前類中能夠被改寫的方法(既不是私有方法,也不是final方法)

代碼示例:線程

public class test {
    public void setAnimals(Animal animal){
        animal.setDag(
            new Dog(){
                public void doSomething(){
                     ...
                };
            }
        )
    }
}

當前類test來講,setDag爲外部方法,Dog就被髮布了。設計

this引用逸出

基於外部方法發佈對象引出this引用逸出問題。直接拿java併發編程實戰的代碼code

public class ThisEscape {
    public ThisEscape(EventSource source){
        source.registerListener(
            new EventListener(){
                public void onEvent(Event e){
                    doSomething(e)
                }
            });
    }
}
java併發編程實戰的解釋:
當ThisEscape發佈EventListener時,它也無條件地發佈了封裝(enclosing)ThisEscape的實例,由於內引類(inner class inst ances)的實例包含了對封裝實例隱含的引用。

這裏發佈new EventListener()內部對象,隱式的有個this。也就是ThisEscape也會被髮布出去,可是ThisEscape尚未構建完成,存在逸出的可能,ThisEscape在未構建完成被髮布了。怎麼處理這個可能逸出的問題,就是讓ThisEscape構建完成再發布出去就能夠了。java併發編程實戰的提到私有構造函數+公共的工廠方法解決可能逸出的問題。對象

public class ThisEscape {
    private final EventListener listener;
    
    private ThisEscape(){
        listener = new EventListener(){
            public void onEvent(Event e){
                doSomething(e)
            }
        };
    }
    
    public static ThisEscape newInstance(EventSource source){
        ThisEscape thisEscape = new ThisEscape();
        source.registerListener(thisEscape.listener);
        return thisEscape;
    }
    
}

同理在構造函數能夠新建線程,當不要start()。start()的話this被新線程共享。下面代碼就是錯誤的:作用域

public class ThisEscape {  
    private Thread thread;  
    public ThisEscape(){    
        thread = new Thread(){  
            public void run(){  
                   ...
            }  
        };  
        thread.start(); //能夠在構造函數中new Thread 可是不要start
    }  
      
    public static void main(String[] args){  
        ThisEscape a = new ThisEscape();  
    }  
}
相關文章
相關標籤/搜索