线程同步和并发

2018-10-10  本文已影响0人  NullBugs

每个线程都有自己的高速缓存,在多线并发过程中,会导致CPU访问到高速缓存的数据不一致,从而导致线程并发问题。

    public synchronized void addSession(){
        mSessionCount++;
    }
    
    public void removeSession(){
        synchronized (this) {
            mSessionCount--;
        }
    }

volatile本质是:jvm当前变量在寄存器中的值是不确定的,需要从主存中读取

private volatile int mSessionCount;

lock锁的状态是可见的,lock锁的类型比较多:可重入锁,读写锁,使用方法更加灵活。lock必须在finally释放,否则可能会造成异常情况下,锁无法释放

    ReentrantLock mLock = new ReentrantLock();
    public void addSession(){
        mLock.lock();
        try{
            mSessionCount++;
        }finally{
            mLock.unlock();
        }
        
    }

ConcurrentHashMap BlockingQueue等数据结构
在java中,由于hashmap等容器是非线程安全的,java提供对用concurrentXXX数据结构,多线程安全,而且效率非常高,有兴趣的同事可以去看下

ThreadLocal比较常用,其本质不是线程同步,而是以空间换时间,每个线程维护自己的副本(在后台并发时比较有用)

    private static ThreadLocal<Integer> sCount = new ThreadLocal<Integer>();
    public void addSession(int count){
        count = ((sCount.get() == null) ? 0 : sCount.get()) + count;  
        sCount.set(count);
    }
    
    public int getSession(){
        return sCount.get();
    }

测试:

for(int i = 0; i < 5; i++){
    new Thread(new Runnable() {
        public void run() {
            s.addSession(1);
            System.out.println("session count : " + s.getSession());
        }
    }).start();
}

结果:

session count : 1
session count : 1
session count : 1
session count : 1
session count : 1

其原因是ThreadLocal在ThreadLocalMap中为每个线程保存了副本,map的key就是Thread本身,ThreadLocalMap持有ThreadLocal的弱引用,保证线程释放资源时的内存泄露问题(ThreadLoacl变量建议设置成private static),ThreadLocal:

static class ThreadLocalMap {

        /**
         * The entries in this hash map extend WeakReference, using
         * its main ref field as the key (which is always a
         * ThreadLocal object).  Note that null keys (i.e. entry.get()
         * == null) mean that the key is no longer referenced, so the
         * entry can be expunged from table.  Such entries are referred to
         * as "stale entries" in the code that follows.
         */
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

    /**
     * Sets the current thread's copy of this thread-local variable
     * to the specified value.  Most subclasses will have no need to
     * override this method, relying solely on the {@link #initialValue}
     * method to set the values of thread-locals.
     *
     * @param value the value to be stored in the current thread's copy of
     *        this thread-local.
     */
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

    /**
     * Removes the current thread's value for this thread-local
     * variable.  If this thread-local variable is subsequently
     * {@linkplain #get read} by the current thread, its value will be
     * reinitialized by invoking its {@link #initialValue} method,
     * unless its value is {@linkplain #set set} by the current thread
     * in the interim.  This may result in multiple invocations of the
     * {@code initialValue} method in the current thread.
     *
     * @since 1.5
     */
     public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }
上一篇 下一篇

猜你喜欢

热点阅读