天天看點

線程安全(2)--多線程逸出分析和正确處理

多線程溢出寫法:

public class thisescape {

    public thisescape(eventsource source) {

        source.registerlistener(new eventlistener() {

            public void onevent(event e) {

                dosomething(e);

            }

        });

    }

}

點評:加粗的這一段隐式this事件線程已經暴露給thisescape構造函數,而構造函數在該類中首先被其他類調用,是以整個this都暴露了。隻要其他線程在thisescape未構造之前(構造傳回狀态)調用這個類,那麼this就會被建立線程共享并識别它(線程溢出)。

是以正确的寫法:

public class thisescape{

    private final eventlistener listener;

    private thisescape() {

        listener = new eventlistener() {

        };

    public static thisescape newinstance(eventsource source) {

        thisescape safe = new thisescape();

        source.registerlistener(safe.listener);

        return safe;

點評:利用工廠模式來規避eventlistener線程溢出,建立的線程無法在構造函數之前共享和識别safe,進而保證線程安全。

我們在做jdbc連接配接一般也是采用工廠模式,但很少考慮是否存線上程溢出的現象,應盡量避免使用靜态塊,是以需要引起足夠的重視。

案例分析:

public class connectionpool {

    private vector<connection> pool;

    private string url="jdbc:mysql://localhost:3306/xxx";

    private string username="root";

    private string password="root";

    private string driverclassname="com.mysql.jdbc.driver";

    /**

     * 連接配接池的大小,連接配接數

     */

    private int poolsize=10;

    private static connectionpool instance =null;

     * 私有的構造方法,禁止外部建立本類的對象,要想獲得本類的對,通過getistance方法

     * 使用了設計模式中的單子模式

    private connectionpool(){

        init();

    }

    private void init(){

        pool =new vector<connection>(poolsize);

        //readconfig();

        addconnection();

    public synchronized void release(connection conn){

        pool.add(conn);

     * 關閉連接配接池中所有資料庫的連接配接

    public synchronized void closepool(){

        for(int i=0;i<pool.size();i++){

            try{

                ((connection)pool.get(i)).close();

            }catch(sqlexception e){

                e.printstacktrace();

            }

            pool.remove(i);

        }

     * 傳回目前連接配接池中的一個對象

    public static connectionpool getinstance(){

        if(instance==null){

            instance=new connectionpool();

        return instance;

     * 傳回連接配接池中的一個資料庫連接配接

    public synchronized connection getconnection(){

        if(pool.size()>0){

            connection conn=pool.get(0);

            pool.remove(conn);

            return conn;

        }else{

            return null;

    private void addconnection(){

        connection conn=null;

        for(int i=0;i<poolsize;i++){

                class.forname(driverclassname);

                conn=drivermanager.getconnection(url,username,password);

                pool.add(conn);

            }catch(classnotfoundexception e){

            }catch(sqlexception r){

                r.printstacktrace();

    private void readconfig(){

        try{

            string path=system.getproperty("use.dir")+"\\dbpool.properties";

            fileinputstream is=new fileinputstream(path);

            properties props=new properties();

            props.load(is);

            this.driverclassname=props.getproperty("driverclassname");

            this.username=props.getproperty("username");

            this.password=props.getproperty("password");

            this.url=props.getproperty("url");

            this.poolsize=integer.parseint(props.getproperty("poolsize"));

        }catch(exception e){

            e.printstacktrace();

            system.out.println("讀取屬性檔案錯誤");

點評:這個連接配接池算是比較健全了,但還是有不足的地方,看下标記的綠色的部分應加上final,橙色加粗部分應加上volatile

繼續閱讀