极速赛车APP下载

threadlocal static_static变量和static const数组区别_c# threadlocal

电脑杂谈  发布时间:2019-08-31 10:01:43  来源:网络整理

threadlocal static_static数组和static const数组区别_c# threadlocal

假设我们有一个连接管理类:

class ConnectionManager {
    private static Connection connect = null;
    private static String url = System.getProperty("URL");
    public static Connection openConnection() {
        if(connect == null){
            try {
                connect = DriverManager.getConnection(url);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return connect;
    }
    public static void closeConnection() {
        if(connect!=null) {
            try {
                connect.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

如果这个类被用在多线程环境内,则会存程安全问题,那么可以对这两个方法添加synchronized关键字进行同步处理,不过这种会大大降低程序的性能,也可以将connection变成局部变量:

class ConnectionManager {
    private Connection connect = null;
    public Connection openConnection(String url) {
        if(connect == null){
            try {
                connect = DriverManager.getConnection(url);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return connect;
    }
    public void closeConnection() {
        if(connect!=null) {
            try {
                connect.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
class ConnectionManagerTest {
    private String url = System.getProperty("URL");
    public void insert() {
        ConnectionManager connectionManager = new ConnectionManager();
        Connection connection = connectionManager.openConnection(this.url);
        //使用connection进行操作
        connectionManager.closeConnection();
    }
    public void update() {
        ConnectionManager connectionManager = new ConnectionManager();
        Connection connection = connectionManager.openConnection(this.url);
        //使用connection进行操作
        connectionManager.closeConnection();
    }
}

static数组和static const数组区别_c# threadlocal_threadlocal static

每个CURD方法都建立新的连接会导致的巨大压力,这里可以有两种解决方案:

使用连接池管理连接,既不是每次都建立、销毁连接,而是从一个连接池里借出可用的连接,用完将其收回。参加MyBatis连接管理(1) | MyBatis连接管理(2)可以发现,这里connection的建立最好是这么的:每个线程希望有自己独立的联结来减少同步问题,程外部希望共用同一个连接来提高的压力,那么使用ThreadLocal来管控连接就是最好的选取了。它为每位线程维护了一个自己的连接,并且可以程内共享。

class ConnectionManager {
    private static String url = System.getProperty("URL");
    private static ThreadLocal<Connection> connectionHolder = ThreadLocal.withInitial(() -> {
        try {
            return DriverManager.getConnection(url);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    });
    
    public static Connection openConnection() {
        return connectionHolder.get();
    }
    public static void closeConnection() {
        Connection connect = connectionHolder.get();
        if(connect!=null) {
            try {
                connect.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

另外还可以用到其他必须每个线程管理一份自己的资源副本的地方:An Introduction to ThreadLocal in Java

c# threadlocal_threadlocal static_static数组和static const数组区别

这上面涉及到三种对象的映射:Thread-ThreadLocal对象-ThreadLocal中存的详细内容,既然是每位线程就会有一个资源副本,那么这个从ThreadLocal对象到存储内容的映射自然才会存在Thread对象里:

ThreadLocal.ThreadLocalMap threadLocals = null;

而ThreadLocal类也是提供了访问这个Map的接口:

public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}
public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}   

c# threadlocal_static数组和static const数组区别_threadlocal static

这个ThreadLocalMap是ThreadLocal的内部类,实现了一个类似HashMap的功能,其外部维护了一个Entry数组,下标就是通过ThreadLocal对象的threadLocalHashCode计算得来。这个Entry继承自WeakReferencethreadlocal static,实现对keythreadlocal static,也就是ThreadLocal的弱引用

static class Entry extends WeakReference<ThreadLocal<?>> {
    /** The value associated with this ThreadLocal. */
    Object value;
    Entry(ThreadLocal<?> k, Object v) {
        super(k);
        value = v;
    }
}

内存模型图如下:

clipboard.png

static数组和static const数组区别_c# threadlocal_threadlocal static

极速赛车APP下载当ThreadLocal Ref出栈后,由于ThreadLocalMap中Entry对ThreadLocal只是弱引用,所以ThreadLocal对象会被回收,Entry的key会成为null,然后在每次get/set/remove ThreadLocalMap中的值的之后,会手动清理key为null的value,这样value也能被回收了。

注意:

如果ThreadLocal Ref一直没有出栈(例如下面的connectionHolder,通常我们应该确保ThreadLocal为单例且全局可访问,所以设为static),具有跟Thread相同的生命周期,那么此处的虚引用便形同虚设了,所以使用完后记得调用ThreadLocal.remove将其对应的value清除。

另外,由于ThreadLocalMap中只对ThreadLocal是弱引用,对value是强引用,如果ThreadLocal因为没有其他强引用而被回收,之后也没有调用过get/set,那么还会产生存储泄露,

在使用线程池时,线程会被复用,那么后面保存的ThreadLocalMap同样也会被复用,会导致线程之间的资源没有被隔离,所以在泛型归还回线程池时要记得调用remove方法。

上面看到ThreadLocalMap是自己推动的类似HashMap的功能,当发生Hash冲突(通过两个key对象的hash值计算得到同一个数组下标)时,它没有采用链表方式,而是采取的线性探测的方式,既当发生冲突后,就线性查找变量中空闲的位置。当数组较大时,这个性能会很差,所以建议尽量控制ThreadLocal的数量。


本文来自电脑杂谈,转载请注明本文网址:
http://www.0531mai.com/a/jisuanjixue/article-121193-1.html

    发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

    • 王晨
      王晨

    • 波尔雪
      波尔雪

      这是教育体制落后的具体体现

      • 赵水秀
        赵水秀

        极速赛车APP下载年年换中国豆苗大学生

    极速赛车双面盘 极速赛车双面盘 极速赛车APP下载 极速赛车双面盘 极速赛车手机官网 极速赛车双面盘 极速赛车APP下载 极速赛车手机版下载 极速赛车APP 极速赛车手机版下载