zoukankan      html  css  js  c++  java
  • JAVA并发编程学习笔记------多线程调优

    1. 多线程场景下尽量使用并发容器代替同步容器

      (如ConcurrentHashMap代替同步且基于散列的Map, 遍历操作为主要操作的情况下用CopyOnWriteArrayList代替同步的List)

      ConcurrentHashMap:分段锁机制,多线程条件下优于HashMap+synchronized的组合方式;
      CopyOnWriteArrayList: 每次修改时都会创建并重新发布一个新的容器副本,从而实现可变性。容器的迭代器保留一个指向底层基础数组的引用,这个数组当前位于迭代器的起始位置,由于他不会被修改,
    所以在对其进行同步时只需确保数组内容的可见性。
    2. 避免死锁
      a)尽量不要在释放锁之前竞争其他锁:一般可以通过细化同步方法来实现,只在真正需要保护共享资源的地方去拿锁,并尽快释放锁,这样可以有效降低在同步方法里调用其他同步方法 的情况
      b)顺序索取锁资源: 如果实在无法避免嵌套索取锁资源,则需要制定一个索取锁资源的策略,先规划好有哪些锁,然后各个线程按照一个顺序去索取
      c)尝试定时锁: Java 5提供了更灵活的锁工具,可以显式地索取和释放锁。那么在索取锁的时候可以设定一个超时时间,如果超过这个时间还没索取到锁,则不会继续堵塞而是放弃此次任务,如下:

    public boolean trySendOnSharedLine(String message, long timeout, TimeUnit unit) throws InterruptedException {
       	long nanosToLock = unit.toNanos(timeout) - estimatedNanosToSend(message);
        	if (!lock.tryLock(nanosToLock, NANOSECONDS)){
           		return false;
    	}
       	 try {
            	return sendOnSharedLine(message);
       	} finally {
           		lock.unlock();
        	}
    } 

    这样可以效打破死锁条件。
    3. Amdahl定理:
      speedup<= 1/(F+(1-F)/N)
      其中,F是串行化比例,N是处理器数量,由上可知,只有尽可能减少串行化,才能最大化地提高可扩展能力。降低串行化的关键就是降低锁竞争,当很多并行任务挂在锁的获取上,就是串行化的表现.
    4. 降低锁竞争
      1)缩小锁的范围
        尽量缩小锁保护的范围,快进快出,因此尽量不要直接在方法上使用synchronized关键字,而只是在真正需要线程安全保护的地方使用
      2)减小锁的粒度
        尽量避免大段的synchronize代码块
      3)减少共享资源的依赖
        在多线程开发中尽量减少对共享资源的依赖,比如对象池的技术应该慎重考虑,新的JVM对新建对象以做了足够的优化,性能非常好,如果用对象池不但不能提高多少性能,反而 会因为锁竞争导致降低线程的可并发性。
      4)使用读写分离锁来替换独占锁
        Java 5提供了一个读写分离锁(ReadWriteLock)来实现读-读并发,读-写串行,写-写串行的特性。这种方式更进一步提高了可并发性,因为有些场景大部分是读操作,因此没必要串行工作。
    5. 切换上下文
      线程比较多的时候,操作系统切换线程上下文的性能消耗是不能忽略的,
    6. 内存同步
      当使用到synchronized、volatile或Lock的时候,都会为了保证可见性导致更多的内存同步,这就无法享受到JMM结构带来了性能优化。
    7. 适当使用同步工具类
      (1) 闭锁(CountDownLatch): 延迟线程的进度直到其达到终止状态,用来确保某些活动直到其他活动都完成后才继续执行;一次性对象,一旦进入终止状态,就不能被重置;
      (2) FutureTask: 可生成结果的Callable,如果有结果可用,那么FutureTask.get将立即返回结果,否则它会一直阻塞,直到结果计算出来再将其返回。
      (3) 信号量(Semaphore):用来控制同时访问某个特定资源的操作数量,或者同时某个指定操作的数量,Semaphore还可以用来实现某种资源池,或者对容器施加边界。
      (4) 栅栏(Barrier): 类似于闭锁,区别在于所有线程必须同时到达栅栏位置才能继续执行,闭锁用于等待事件,而栅栏用于等待其他线程。可被重置用于下次使用。两种实现方式:CyclicBarrier,Exchanger

     8. 实际情况中,应尽可能的使用现有的线程安全对象(例如AtomicInteger)来管理类的状态

     9. 在多线程程序中使用共享且可变的long和double等类型的变量也是不安全的,除非用volatile来声明它们,或者用锁保护起来。

  • 相关阅读:
    将地址转换为链接的正则表达式(regex url href)
    [收藏]中国惠普前总裁孙振耀谈人生
    沪江技术团队寻觅新成员,下一位会是你吗?
    来点圣诞气氛
    让VisualSVN Server支持匿名访问
    11月25日博客园南京园友聚会
    [上海俱乐部活动]博文视点与博客园系列图书作者见面会暨.NET技术交流会
    比尔·盖茨在微软的最后一天
    真让人兴奋
    博客园新服务器已下订单
  • 原文地址:https://www.cnblogs.com/hunterCecil/p/8387057.html
Copyright © 2011-2022 走看看