关于java并发编程的一些概念及策略

最近抽出了点时间,把java并发编程的一些概念和策略总结了一下:

1. 同一个程序中的多个线程能够被同时调度到多个CPU上(利用这一点一般能提升cpu的使用率) java

2. 多线程运用的例子:RMIServletGUI(一般状况下:GUI对象都只能在实事件线程中访问且GUI的对象是被封闭在  单个线程当中)、Timer 算法

3. 只有当类中仅包含本身的状态时,线程安全类才是有意义的 编程

4. 在必定条件下,能够安全地放宽状态变量的封装性 缓存

5. 同步术语:sychronizedvolatile类型的变量、显式锁、原子变量(concurrent包中) 安全

6. 最多见的竞态条件:先检查后执行(check-and-act),读取--修改--写入 多线程

7. 内置锁:可重入(可重复获取相同的锁) 并发

8. 在构造方法中能够建立线程,但最好不要启动线程,以防止启动的线程访问未彻底构造的this引用 app

9. 构造方法中调用非privatefinal方法(即有可能被复写的方法),也会致使this引用逸出 函数

10. 线程封闭的三种方式:Ad-hoc线程封闭、栈封闭、ThreadLocal 高并发

11. final域(引用不指向可变对象的状况下)是线程安全的

12. 安全发布对象的经常使用模式:

①. 在静态初始化函数中初始化一个对象引用

②. 将对象保存到某个正确构造对象的final类型域中

③. 将对象的引用保存到volatile类型的域或者AtomicReference对象中

④. 将对象的引用保存到一个由锁保护的域中

13. 在并发编程中使用和共享对象时的策略:

①. 线程封闭

②. 只读共享

③. 保护对象(持有特定的锁)

④. 线程安全共享(线程安全的对象提供的公共访问接口)

14. 在现有的安全类中添加功能:

①. 经过继承扩展

②. 经过辅助类(客户端加锁机制)

③. 经过类的组合

15. 特定状况能够考虑并发容器替代同步容器

   同步容器:将全部的对容器状态的访问都串行化,以实现线程安全(如:Vector

   并发容器:经过快照(如:CopyOnWriteArrayList)、分段锁(如:ConcurrentHashMap)等方式实现线程安全

16. 利用BlockingQueue实现“生产者——消费者”模式;利用BlockingDeque实现“工做密取”模式

17. 中断线程的通常处理方法:

  第一种:run方法中无循环体

public void run(){
   If(Thread.isInterrupted()){
   return;
   }
}

 第二种:run方法中有循环体

public void run(){
  for(;;;){
    If(Thread.isInterrupted()){
      break;
    }
  }
}

第三种:抛出中断异常结束程序

public void doEverIfNoException()  throws  InterruptedException{
     If(Thread.isInterrupted()){
        throw new InterruptedException();
     }
}

在执行currentThread.interrupt以后,也能够经过调用Thread.sleep或者obj.wait或者currentThread.join使线程抛出中断异常后结束,但JVM并不能保证阻塞方法检测到中断的速度(一般状况下仍是很是快的)。

第四种:利用一个标志位来控制程序

public void run(){
   valotile isCancled = false;
     while(!isCancled){
        doSomething();
     }
}

 18. 一些经常使用的同步工具类:闭锁(如:CountDownLatch, FutureTask),信号量(如:Semaphore),栅栏(如:CyclicBarrier, Exchanger

19. 在使用Thread的地方,考虑若是使用Executor是否能得到更好的效果

20. 一般用ScheduledThreadPoolExecutor来替代Timer来执行延迟任务与周期任务

21. 递归算法的并行化处理(每一次递归都不存在依赖关系时)

22. 注意经过控制获取“锁”的顺序的一致性来避免“死锁”,也能够尝试使用“定时锁”,同时要注意不要相信“线程的优先级”(由于它对平台具备依赖性),最后不要忘记防止“活锁”(在一个线程内重复执行某一操做,使线程没法继续向下执行)

23. 在试图提升并发程序的性能时,要注意程序的“可扩展性”和“安全性”,并以测试为基准,不要猜测

24. 线程引入的开销:上下文切换、内存同步(如:经过刷新缓存是缓存无效)、阻塞(Spin-waiting方式,操做系统挂起被阻塞线程)

         注:阻塞致使线程在其执行的时间片还未用完以前就被交换出去,而在随后当要获取的锁或者其余资源可用时,又被切换回来

25. 减小锁的竞争3种方式:

①. 减小锁的持有时间(如:缩小锁的范围)

②. 下降锁的请求频率(如:减少锁的粒度,但采用此种方法应该考虑上下文切换频率增高带来的额外开销)

③. 使用带有协调机制的锁(如:定时锁)

26. 在激烈竞争状况下,ReentrantLock非公平锁性能高于其公平锁,缘由:在恢复一个被挂起的线程与该线程正在开始运行之间存在着严重的延迟

27. ReentrantLock的特性包括:可定时、可轮询、可中断、公平队列、非块结构

28. ReentrantReadWriteLock支持多个线程同时读取,但支持一个线程写入,写锁能够降级为读锁,读锁不能升级为写锁(读锁升级为写锁可能致使死锁)

29. 必要时能够构造本身的同步工具(大多数的开发者这一辈子都不须要这么作,缘由你懂得!)

30 显示的Condition对象,不知你们用过没有?能够用来控制“多生产者---多消费者”模型

31. CAS------原子变量-------锁,这些在不一样场景下的性能能够好好分析比较一下

32. 双重检查的罪恶:

public class DoubleCheckedLocking {
    private static Resource resource;

    public static Resource getInstance() {
        if (resource == null) {   //此处可能致使获到不完整的对象  
              synchronized (DoubleCheckedLocking.class) {
                if (resource == null)
                    resource = new Resource();
            }
        }
        return resource;
    }

    static class Resource {

    }
}

双重检查的替代方案:延迟初始化占位类模式

public class ResourceFactory {
    private static class ResourceHolder {
        public static Resource resource = new Resource();
    }

    public static Resource getResource() {
        return ResourceFactory.ResourceHolder.resource;
    }

    static class Resource {
    }
}

33. Java内存模型的Happens-Before规则(有精力的看看吧,但实际应用中一般仍是借助同步来控制操做的顺序)

相关文章
相关标签/搜索