线程安全(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 void onEvent(Event e) {
                doSomething(e);
            }
        };
    }
    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++){
            try{
                Class.forName(driverClassName);
                conn=DriverManager.getConnection(url,username,password);
                pool.add(conn);
            }catch(ClassNotFoundException e){
                e.printStackTrace();
            }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

原文地址:https://www.cnblogs.com/clnchanpin/p/7149589.html