Interview some manufacturers can not do without --ThreadLocal, its implementation principles Did you know?

scenes to be used

Suppose we have a database connection management categories:

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();
            }
        }
    }
}

If the class is used in a multi-threaded environment, thread-safety problems will exist, you can add the synchronized keyword synchronize the two methods, but it will greatly reduce the performance of the program can also be turned into a local variable 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();
    }
}

Each CURD methods to create a new database connection will cause great pressure on the database, where you can have two solutions:

  1. Use connection pool to manage connections, is neither created every time, destroy a connection, but the loan available connection from a connection pool, it will run out of return.

  2. It can be seen here, the best connection is established is this: each thread has its own independent connection hope to avoid synchronization problems, internal thread wish to share the same connection to reduce the pressure on the database, then use ThreadLocal to manage the database connection is the best choice. It maintains its own connection for each thread, and can be shared within a thread.
class ConnectionManager {
    private static String url = System.getProperty("URL");
    private static ThreadLocalconnectionHolder = 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();
            }
        }
    }
}

It also can be used every other thread management need a copy of your local copy of the resource: An Introduction to ThreadLocal in Java

The principle

This mapping which involves three kinds of objects: the specific content of Thread-ThreadLocal objects -ThreadLocal in existence, since each thread will have a copy of the resource, then the stored content from ThreadLocal object to the mapping will naturally exist Thread objects in :

ThreadLocal.ThreadLocalMap threadLocals = null;

The ThreadLocal class only provides an interface to access the Map of:

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);
}

This is ThreadLocalMap ThreadLocal internal class that implements a function similar HashMap, which maintains an internal Entry array subscript is calculated by threadLocalHashCode ThreadLocal object come. The Entry inherited from WeakReference, to achieve the key, that is, the weak references ThreadLocal:

static class Entry extends WeakReference<threadlocal
    /** The value associated with this ThreadLocal. */
    Object value;

    Entry(ThreadLocal k, Object v) {
        super(k);
        value = v;
    }
}
</threadlocal

FIG memory model as follows:

Interview some manufacturers can not do without --ThreadLocal, its implementation principles Did you know?

Ref ThreadLocal When the stack, since the Entry ThreadLocalMap ThreadLocal reference only weakly, so ThreadLocal object will be recovered, the Entry key becomes null, then the value / set / remove ThreadLocalMap get in each time, it will be automatically cleanup key to null value, this value can also be recovered.

Note: If ThreadLocal Ref has not popped (such as the above connectionHolder, usually we need to ensure that patients and ThreadLocal single globally accessible, so set static), with Thread have the same life cycle, so here is a virtual reference will exist in name only , so remember to call ThreadLocal.remove after use to remove its corresponding value.

In addition, because of the ThreadLocalMap ThreadLocal is only a weak reference, is strong reference for value, if ThreadLocal because there is no other strong references and recovered, after also did not call off get / set, it will produce a memory leak,

When using the thread pool thread will be reused, then saved inside ThreadLocalMap will also be reused, will result in resources between threads are not isolated, so the thread to remember to call the remove method to return back to the thread pool.

hash conflict

ThreadLocalMap above-mentioned functions are similar HashMap their implementation, when the Hash collision occurs (resulting in the same array index via two key hash value calculation objects), it does not use the list mode, instead of using linear probing methods not only when conflict occurs, the linear array to find vacant position.

When the array is large, the performance will be poor, it is recommended to control the number of ThreadLocal.

Guess you like

Origin blog.51cto.com/14230003/2477129