首页

Java并发编程基础知识分享(源码剖析及示例分析)

标签:多线程,ppt,死锁,非阻塞,JAVA,concurrent,Volatile,单例,Synchronized,ReentrantLock,公平锁,ThreadLocal,CopyOnWrite,Semaphore,线程池,CountDownLatch,CAS,AtomicInteger,AtomicReference,ConcurrentLinkedQueue,CurcurrentStack     发布时间:2016-07-05   

一、并发用例场景

对于用户并发编程常用场景有静态资源池、分布式异步调度系统、规则处理引擎、HTTP服务引擎(web服务)及文件处理服务器(如自定义打印服务器)等等,下面举个单例资源调用的例子,如下所示

public class UnsafeLazyInitialization {@b@	private static Object instance;@b@	public static Object getInstance(){@b@	   if(instance==null)//线程1访问@b@	     instance=new Object();//线程2访问@b@	   return instance;//两线程有可能都创建了各自的对象@b@	}@b@}

上面代码实现的单例,对于多线程访问的时候,各自cpu处理器在切换各自上下文数据未能及时同步Memory内存中(如下图),可能造成会获取多个对象

Java并发编程基础知识分享(源码剖析及示例分析)

二、并发或多线程锁同步

对于大数据处理或多业务流程接口调度都避免不了IO的延时处理等待,通过CPU的并发处理能力将串行IO延时改为并行IO,从而缩短了等待时间,对于并发多线程处理需要解决最多的就是数据状态的一致性问题,这时需要引入锁、Volatile变量、ThreadLocal等方式来同步数据状态。

1. 锁

按照实现方式分为JVM级别实现的Synchronized和JAVA并发包类级别虚拟锁ReentrantLock,具体用法示例可参考“关于线程同步使用synchronized和Lock对比及代码示例

Synchronized:JVM级别的锁,是JVM的内置属性,可以重入,对于前言中的例子,我们可以加入Synchronized解决问题,如下所示

public class SafeLazyInitialization {@b@    private static Object instance;@b@    public static Object getInstance(){@b@        synchronized (UnsafeLazyInitialization.class) {@b@            if(instance==null)//线程1访问@b@                instance=new Object();//线程2访问@b@        }@b@        return instance;//两线程有可能都创建了各自的对象@b@    }@b@}

类在加载时,有把初始化锁,如下图所示

Java并发编程基础知识分享(源码剖析及示例分析)

所有对于上面单例,还可以通过类的加载锁来实现,代码如下

public class SafeLazyInitialization {@b@    private SafeLazyInitialization () {@b@    }@b@    private static class InstanceHolder {@b@        public static SafeLazyInitialization instance = new SafeLazyInitialization();@b@    }@b@    public static SafeLazyInitialization getInstance() {@b@        return InstanceHolder.instance; // 这里将导致InstanceHolder类被初始化@b@    }@b@}

ReentrantLock:  JAVA类库级别的,功能更多:支持等待可中断,公平锁等等

按照公平性分为公平锁和非公平锁

2. Volatile变量

写操作会立即反应到其他线程之中(对一个volatile变量的读,任意线程总是能看到对这个变量最后写入的值);对任意单个volatile变量的读写具有原子性,类似于volatile++这种复合操作不具有原子性

3. ThreadLocal

为每一个使用该变量的线程提供独立的变量副本

/**@b@     * Returns the value in the current thread's copy of this@b@     * thread-local variable.  If the variable has no value for the@b@     * current thread, it is first initialized to the value returned@b@     * by an invocation of the {@link #initialValue} method.@b@     * @return the current thread's value of this thread-local@b@     */   @b@public T get() {@b@        Thread t = Thread.currentThread();@b@        ThreadLocalMap map = getMap(t);@b@        if (map != null) {@b@            ThreadLocalMap.Entry e = map.getEntry(this);@b@            if (e != null) {@b@                @SuppressWarnings("unchecked")@b@                T result = (T)e.value;@b@                return result;@b@            }@b@        }@b@        return setInitialValue();@b@}  @b@/**@b@     * Sets the current thread's copy of this thread-local variable@b@     * to the specified value.  Most subclasses will have no need to@b@     * override this method, relying solely on the {@link #initialValue}@b@     * method to set the values of thread-locals.@b@     * @param value the value to be stored in the current thread's copy of@b@     *        this thread-local.@b@     */@b@     @b@public void set(T value) {@b@        Thread t = Thread.currentThread();@b@        ThreadLocalMap map = getMap(t);@b@        if (map != null)@b@            map.set(this, value);@b@        else@b@            createMap(t, value);@b@}