CopyOnWriteArraySet<E>和CopyOnWriteArrayList<E>

CopyOnWriteArraySet<E>和CopyOnWriteArrayList<E>

 

CopyOnWrite ArraySet<E>类图

CopyOnWriteArrayList<E>

CopyOnWriteArrayList<E>类是ArrayList<E>的线程安全版本。一句话很清楚的说明了CopyOnWriteArrayList<E>的作用,注释中同样指出了实现了原理:任何改变数组的操作都是在内部数组的一个新的拷贝上进行的。这样的实现对于写来说代价很大,但如果多线程环境下遍历的操作,读操作远远多于写操作来说就比较高效了。因此应用的场景就是:在多线程环境下一个读操作远远多于写操作的列表。

线程安全最简单的做法就是同步,那我们从源码的角度来看下ConpyOnWriteArrayList<E>相对于直接在ArrayList<E>上进行操作的同步比较起来的改进之处:写操作在可重入锁的保护下在内部数组的拷贝上进行,操作完成后将内部数组换成最新的数组。这样读操作就不许要进行同步,避免了直接同步ArrayList<E>时对读操作带来的开销。

    public boolean add(E e) {

        final ReentrantLock lock = this.lock;

        lock.lock();

        try {

            Object[] elements = getArray();

            int len = elements.length;

            Object[] newElements = Arrays.copyOf(elements, len + 1);

            newElements[len] = e;

            setArray(newElements);

            return true;

        } finally {

            lock.unlock();

        }

}

    //读操作不做同步保护

public E get(int index) {

        return get(getArray(), index);

    }

Iterator操作

         CopyOnWriteArrayList<E>的Iterator返回的迭代器是COWIterator<E>,实际迭代的内容是调用Iterator是列表的一个快照,因此可以很快的迭代整个序列,但是因为是快照,所以无法通过迭代器的写操作来改变原先的列表,所以该迭代器的写操作都会抛出异常,如:

        private COWIterator(Object[] elements, int initialCursor) {

            cursor = initialCursor;

            snapshot = elements;

        }

//COWIterator的remove,set,add操作都会抛出异常

public void remove() {

            throw new UnsupportedOperationException();

        }

 

CopyOnWriteArraySet<E>

CopyOnWriteArraySet<E>内部的本质使用的就是CopyOnWriteArrayList<E>再实现java.util.Set接口来实现Set的操作,因此同样具有以下特点:

1.      适用于数量不大,读操作远远多于写操作,需要多线程安全的。

2.      写操作的代价非常高。

3.      迭代器Iterator不支持remove等写操作,带迭代器的读很快。

 

    private final CopyOnWriteArrayList<E> al;

 

    /**

     * Creates an empty set.

     */

    public CopyOnWriteArraySet() {

        al = new CopyOnWriteArrayList<E>();

}

 

    public boolean add(E e) {

        return al.addIfAbsent(e);

}

    public Iterator<E> iterator() {

        return al.iterator();

    }

 

具体应用

Java.sql.DriverManager中用来保存注册过的所有Driver信息。该应用场景实际上就是依次注册,后此多次遍历使用的场景,同时需要提供线程安全的特性。

Java.sql.DriverManager:

private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<DriverInfo>();

 

//  Worker method called by the public getConnection() methods.

    private static Connection getConnection(

        String url, java.util.Properties info, Class<?> caller) throws SQLException {

        /*

         * When callerCl is null, we should check the application's

         * (which is invoking this class indirectly)

         * classloader, so that the JDBC driver class outside rt.jar

         * can be loaded from here.

         */

        ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;

        synchronized (DriverManager.class) {

            // synchronize loading of the correct classloader.

            if (callerCL == null) {

                callerCL = Thread.currentThread().getContextClassLoader();

            }

        }

 

        if(url == null) {

            throw new SQLException("The url cannot be null", "08001");

        }

 

        println("DriverManager.getConnection(\"" + url + "\")");

 

        // Walk through the loaded registeredDrivers attempting to make a connection.

        // Remember the first exception that gets raised so we can reraise it.

        SQLException reason = null;

        //遍历注册的驱动信息,获取url对应的驱动类。

        for(DriverInfo aDriver : registeredDrivers) {

            // If the caller does not have permission to load the driver then

            // skip it.

            if(isDriverAllowed(aDriver.driver, callerCL)) {

                try {

                    println("    trying " + aDriver.driver.getClass().getName());

                    Connection con = aDriver.driver.connect(url, info);

                    if (con != null) {

                        // Success!

                        println("getConnection returning " + aDriver.driver.getClass().getName());

                        return (con);

                    }

                } catch (SQLException ex) {

                    if (reason == null) {

                        reason = ex;

                    }

                }

 

            } else {

                println("    skipping: " + aDriver.getClass().getName());

            }

 

        }

 

        // if we got here nobody could connect.

        if (reason != null)    {

            println("getConnection failed: " + reason);

            throw reason;

        }

 

        println("getConnection: no suitable driver found for "+ url);

        throw new SQLException("No suitable driver found for "+ url, "08001");

    }

 

 

Com.mysql.jdbc.Driver:

//如com.mysql.jdbc.Driver类启动时会调用DriverManager.registerDriver方法来注册mysql

//的驱动信息

package com.mysql.jdbc;

 

import java.sql.DriverManager;

import java.sql.SQLException;

 

public class Driver extends NonRegisteringDriver

  implements java.sql.Driver

{

  static

  {

    try

    {

      DriverManager.registerDriver(new Driver());

    } catch (SQLException E) {

      throw new RuntimeException("Can't register driver!");

    }

  }

}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值