最近重新读java concurrency in practice 随笔

觉得自己在并发编程还缺很多, 最近一段时间都在积极的学习中。 呵呵, 学到老, 活到老。 

Java 的并发编程涉及的方面还是非常多的:

1,  基础方面的: 对象的共享。 依照从安全性从高到低的方式 可以有

  •      最安全的对象共享就是不享, 一个对象仅仅局限在一个线程中。 如果一个对象只能被某个线程的局部变量 也就是在 栈(stack) 访问。
  •      ThreadLocal 也是一种非常安全的方式
  •      不可变对象  也就是对象的所有域都是final , 并且对象在建构函数中并没有this 指针的逃逸问题。
  •       普通对象    所有在线程之间并发 read/write 的方法都通过锁 来保护。

    接下来是并发编程会用到得一些常用的并发容器, 队列, 同步工具什么的

  •         并发容器   ConcurrentHashMap,  CopyOnWriteArrayList
  •         并发编程中最常用的生产者/ 消费者模式中常用的 ConcurrentLinkedQueue,  LinkedBlockingDeque。 如果要Queue 的队列大小有限的话都会涉及到 blocking 的问题。 在队列已满的情况下 再朝queue 里面插入元素会让当前线程 wait。
  •        常用的同步工具  各种 Latch,  Semaphore, Barrier。 CountDownLatch 是最常用的一种Latch, 设置一个初始值。需要等待的线程调用 await 方法, 其它线程可以 调用 countDown 来递减这个计数器。 当counter 到 0了, 所有等待这个Latch的线程都会被唤醒。  

2, 并发程序的结构

      2.1,  Callable/  Future

             Runnable 的局限是没有返回值,

                interface Callable<R> {
			R call() throws Exception
		}

             不光是有了返回值, 还有 Exception。 

            Future 表示了一个异步调用的结果

      public interface Future<V> {

    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

            这个接口的实现通常是  get 方法只有在 isDone 的时候才马上返回, 否则它会等待。 但是有了这个Future 可以将运行线程的Callable 结果安全的传递给另外一个线程。  

      2.2,  Execotor  执行框架

在JDK的  java.utility.concurrency (JUC) 包中 定义了 Execotor  这个仅仅有一个execute 方法, 另外ExecutorService 接口扩展了它。 不仅提供了管理life cycle 的方法外, 还包括了 submit  Runnable, submit  Callable 的方法。  另外 invokeAll,  timeout 版的invokeAll 也是非常有用的。  

      2.3,  取消, 中断 , stop

                service,生命周期的安全性也是非常重要的。 

      2.4, 线程池

               ThreadPoolExecutor

              JUC 的Executors 工厂类提供了几个非常有用的ExecutorService

                       newFixedThreadPool  固定线程数目的线程池

                       newSingleThreadExecutor 创建单线程的Executor  一个线程来run 所有的task , 这样不会有撒并发的问题

                       newScheduledThreadPool   可以 schedule commands。有了这个Service 可以忘掉以前的Timer 了。

3,  高级主题

       1,  减少锁的竞争

              一些常用的手段无非是尽量少用 锁,  降低锁的粒度,  降低锁的访问。 

       2,  instrinsic 锁 与 ReentrantLock 的比较

                  instrinsic logic  也就是 synchronized 的关键字的运用 主要借助java 中 任何一个Object 都有一个wait 队列。   这个synchronized 用的时候 锁的获取与释放必须在同一个block 或者方法中。 

                 ReentrantLock 就比较自由, 但是比较担心没有 unlock, 因此永远不要忘了 try/finally 的方式来用它。

                 ReentrantLock 可以做到 tryLock,  甚至可以用 timeout 方式在限定时间来获取锁。  

         ReentrantLock  可以选择 fair /unfair 方式

                 ReentrantLock  等待的线程还可以响应 interrupt 。

       3,  怎样自定义新的同步工具

怎么来借助现有的工具来定制自己有用的新的工具。这块做的还不多, 以后再仔细琢磨吧。              

       4,  非阻塞机制

              借助硬件的 CAS 也就是 comare and swap 。 如果比较成功再交换, 这整个动作都是 原子操作。  原理跟数据库中的 乐观锁的概念是一致的。 先拿出要操作的东西的当前值, 修改它。 在提交的时候 新值和老值都作为参数传入。  CAS 比较 传入的old value 与当前值做比较, 如果相同证明没有其它线程操作。否则直接返回false。 

        5, Java 内存模型  也就是JSR 133 里面的东东。主要涉及的有  re-order,  volatile, final,  happen-first 。 这个刚刚看过就略过。  它有提到 讲得比较多的 double lock 机制来实现 延迟创建 单例。  在新的 1.6 里面的 jvm 里面应该不会再 有什么 java 对象内存分配了 建构函数还在执行 就返回非null 的情况吧。 保险起见就用 JMM 里面明确的 happen-before 机制 像final 域的 initializer,内部static 类 的加载 应该都可以保证安全。  安全第一,呵呵。

暂时就这么多料,  中英文版本配合起来看 效果还可以。  机械工业出版社出版的那个中译本太水了, 很多时候得看英文版,  毕竟在Kindle DXG 看英文版没有实体中文书方便。  

猜你喜欢

转载自bruce008.iteye.com/blog/1460344
今日推荐