`

多线程摘录 001

阅读更多

需要考虑什么?
* 正确性. 程序必须能得到正确的结果
* 生存性. 程序必须能稳定有效运行
* 安全性. 例如不造成资源共享问题等...
* 性能.

Timer: 它自己管理了线程来处理TimerTask.

使线程安全运行的一些方法:
* 不共享内部状态, 如使用无状态的设计
* 使用不变模式
* 使用同步

线程对资源使用的原子性:
如果线程两次访问资源, 得到的不是相同的状态, 就有原子性的问题.
通常线程对共享资源的竞争(如没有同步, 混合操作set,get等)会造成原子性问题.
设计良好的类也可能因为继承而造成原子性问题, 因为子类可能没有遵守父类处理资源状态的规则
单例模式中, 如果用的是延迟加载的模式, 也有原子性问题.

JDK5引入了新的并发机制, 其基本思想仍然是同步, 但是具体的做法是最大限度的缩小使用同步的粒度, 使得同步只发生在共享资源内部, 比如AtomicLong, 由JVM保证了不会对其进行影子操作(如两线程同时访问增加操作,保证两个增加操作是串行的. 这些机制相当于volatile语义上的等价物, 只是更适合应用.

锁:
锁是实现同步的一种手段, 保证资源访问的独占性. 有乐观锁和悲观锁.

JDK提供的synchronized关键字是可重入的锁定, 即, 当占据了资源的线程释放了资源后, 所有在等待该资源的线程重新竞争以获取对资源的锁定.

提高性能:
如果原来的同步是方法层面的或者很大一块同步, 那么考虑把这个大范围的同步拆分成几个小范围的同步, 也是提供性能的一个方式, 因为拆分后, 不同的线程可以在不同的同步块内执行, 是"半并发"的形式.

考虑资源状态的可见性, 是否产生过期数据
(32位操作系统上的?) 64位数据操作可能出现非原子性操作, 即对64位数据(long,double)要进行高低32位操作, 中间的间隔就可能出现问题

什么时候使用volatile变量.

不好翻译, 摘出原文来
Use volatile variables only when they simplify implementing and verifying your synchronization policy; avoid using volatile variables when veryfing correctness would require subtle reasoning about visibility. Good uses of volatile variables include ensuring the visibility of their own state, that of the object they refer to, or indicating that an important lifecycle event (such as initialization or shutdown) has occurred.

只有在简化实现和验证同步策略的时候才应该使用volatile, 如果验证正确性需要某种莫名其妙的关于可见性的理由, 就要避免使用volatile. 对volatile变量的正确使用, 包括保证引用到的对象正确的状态, 或者是指明一种重要的生命周期事件(如初始化和关闭)的发生.

下面是一个正确使用volatile的例子:
volatile
boolean asleep;
...
while (!asleep) {
   countSomeSheep();
}
因为这里没有使用同步(synchronized), 如果没有加上volatile, 那么, 就有可能线程A在第一个时刻修改了asleep的值, 然而仍没有写入主内存的时刻, 线程B访问了asleep, 取得的是旧的值. 【注:此处应参考java内存模型】.

状态泄漏
公布一个对象或者状态意味着把信息传递到一个线程可触及的范围之外,同时也可能造成内部状态"不经意"的泄漏出去. 包括引用到的内部对象, this等. 这些方式如:
1) return new EventListener(this);
2) private String[] status; public String[] getStatus(){return status;}
3) source.registerListener(new EventListener(){ //内部匿名类隐含了this
        public void onEvent(Event e){ dosomething(e); }
    }
不过应该考虑这些"泄漏"是否真的会有影响. 对于匿名内部类的问题, 如果要禁止this被意外引用, 可以定义为局部变量即可

避免资源共享冲突: 锁住资源

比如Swing的控件, 全部被锁定在event dispatch线程范围内, 比如JDBC连接池, 通常它的客户端只是单个线程处理单个请求, 因为只要连接池不在某个连接被申请后再分配给其他线程, 就是安全的.
局部变量是线程安全的, 因为只能在线程的方法栈的范围内能引用到; 也可以考虑使用ThreadLocal, 因为ThreadLocal是绑定到线程的临时存储区.

采用不变模式的设计
如果对象从初始化之后就是保持不变的状态, 无疑是线程安全的. 比如只有构造函数和getter, 没有setter的类. 当然这只是个大致方向, 如果getter返回了对象的引用, 能被随意修改, 这个类也不能称为不变了. 又或者使用final关键字

技巧分析: 只使用volatile来实现线程安全

public class VolatileCachedFactorizer implements Servlet {
    //
注: OneValueCache 是一个不变模式的对象, 是通过copy构造参数的方式来实现的
    private volatile OneValueCache cache =
        new OneValueCache(null, null);

    public void service(ServletRequest req, ServletResponse resp) {
        BigInteger i = extractFromRequest(req);
        BigInteger[] factors = cache.getFactors(i);
        if (factors == null) {
            factors = factor(i); //
factor(i)是一个private方法.
            cache = new OneValueCache(i, factors);
        }
        encodeIntoResponse(resp, factors);
    }
}

代码不多, 主要目的是把最后一次结果缓存起来. 因为factors = factor(i);是在一个线程的范围内单独完成的, factors不会被其他线程引用到, cache = new OneValueCache(i, factors); 这一行, 是copy了factors来构造OneValueCache, 并且cache变量是volatile, 一旦OneValueCache对象构造完毕, JVM会马上把它写入主内存, 确保中间写入过程的原子性.

安全发布对象的流程
1) 使用静态初始化的方式来初始化对象
2) 把该对象赋予volatile变量或者AtomicReference
3) 或者把该对象赋予final变量
4) 或者把该对象赋予由锁定确保安全性的变量. 如一些容器类(Vector...)

一些集合框架提供的线程安全的类:

* Hashtable,
synchronizedMap,ConcurrentMap
*
Vector, CopyOnWriteArrayList, CopyOnWriteArraySet, synchronizedList, synchronizedSet
* BlockingQueue, ConcurrentLinkedQueue

什么样的策略是
线程并发安全中最有用的?
1) 限制对象于线程范围内
2) 只读共享
3) 安全共享. 被共享对象有内部的线程安全机制
4) 锁定保护


转自http://hi.baidu.com/iwishyou2/blog/index/2

分享到:
评论

相关推荐

    delphi多线程编程学习

    在Delphi编程环境中,多线程技术是一种强大的工具,它允许程序同时执行多个任务,从而提高应用程序的响应性和效率。本教程将引导你深入理解Delphi中的多线程编程,并通过实例来帮助你掌握相关技能。 一、多线程概念...

    c语言多进程多线程编程.pdf

    《C语言多进程多线程编程》是一本深入探讨C语言在并发编程领域的专业书籍。在计算机科学中,进程和线程是操作系统中并行执行任务的基本单位,理解和掌握它们对于提升程序性能和优化资源利用至关重要。这本书籍针对...

    C#下多线程实现实例----一个图形化的排序算法演示程序.pdf

    从内容摘录中无法直接得知程序是如何处理线程同步问题的,但可以确定在多线程环境中运行排序算法时,这一点尤为重要。 图形化展示排序过程的核心是ShowData方法。这个方法使用了Windows Forms中的Graphics类来绘制...

    一个很不错的VC++ 多线程应用例子

    摘要:VC/C++源码,系统相关,多线程 与VC++爱好者们分享一个很不错的多线程MultiThread应用例子,你可将之中的模块摘录出来供需要者使用。本多线程模块实例以新建文件写入数据为操作目的,创建多个线程分别创建文件,...

    《Java与模式 阎宏 摘录》.doc 更新中……

    同时,他可能会讨论Java的特性,如多线程、反射、泛型等,以及这些特性和设计模式的结合使用。 通过对《Java与模式 阎宏 摘录》的学习,开发者不仅可以提升自己的编程技巧,还能深入了解如何在实际工作中选择和应用...

    VB异步执行线程的实例源代码

     A:晕,这最终还是调用了老汉多线程……那和线程也没什么区别吧……你应该再试一试线程池……  B:不完全是,因为纤程要先ConvertThreadToFiber,才能CreateFiber,VB中就一个线程,你把它Convert成纤程,那纤程...

    ucgui源程序摘录

    这部分可能涉及到在多线程环境中保护GUI资源的同步机制。在Windows环境下,可能使用标准的互斥对象来实现这一功能,而在其他环境(如单片机)中,可能需要自定义的解决方案。 总的来说,ucgui是一个提供图形用户...

    C++经典笔试和面试摘录

    包括了c++经典笔试题,多线程编程,操作系统,数据库,网络相关知识。以及一些经典面经

    ACE摘录&总结

    ACE Reactor框架是其核心部分之一,它是一个事件多路分离器,能够在一个进程或线程中处理多个客户端连接的事件。使用Reactor框架开发用户程序相对简单,主要包括三个步骤:首先,从`ACE_Event_Handler`派生出子类并...

    vilatile

    根据提供的文件信息,我们可以推断出这部分内容主要讨论了多线程编程中的关键概念与技术。下面将基于这些有限的信息,展开对多线程编程中的一些核心知识点进行详细阐述。 ### 多线程编程概述 多线程编程是现代软件...

    摘录有关vb的资料

    《精通VB.pdf》:这是一本高级教程,旨在帮助读者从熟悉VB到精通,内容可能涉及更复杂的编程概念和技术,如面向对象编程、高级控件应用、多线程处理、网络编程等,有助于提升编程技能。 《VB-函数-速查手册.pdf》:...

    单例设计模式个人总结+摘录

    2. **控制共享资源的访问**:在多线程环境下,可以确保共享资源被正确地管理,避免资源竞争问题。 3. **简化配置过程**:单例模式下的对象通常作为配置或参数传递给其他对象使用,简化了配置过程。 #### 实现方式 ...

    全国各个软件公司面试题---DOTNET笔试题集(摘录)

    可以通过锁(lock)机制、读写锁、线程静态字段(ThreadStaticAttribute)等方式确保多线程环境下的安全性。 #### 4.3 什么是装箱与拆箱? 装箱是指将值类型转换为引用类型的过程;拆箱则是相反的过程。这在使用泛型...

    资深攻城狮解读5个被误解的CPU/GPU概念

    相反,多线程技术可以在较少核心的情况下提供更好的性能提升,因为它可以在同一核心上同时执行多个线程,增加处理效率,并且在开发难度、功耗和面积上,多线程技术更有优势。作者提出未来CPU发展不应只是在多核上...

    Python语言程序设计教程.pptx

    本资源是关于Python语言程序设计的教程,总共分为10章,涵盖了Python编程语言的基础知识、数据类型、控制结构、函数、模块、文件处理、异常处理、面向对象编程、多线程编程等方面的内容。 第一章至第四章主要介绍了...

    参考文献辅助管理软件CvtCNKI

    线程.rar可能包含的是关于CvtCNKI的多线程下载技术文档,这通常意味着软件可能利用多线程技术加速从CNKI等网站下载文献,提高效率,尤其对于大量文献的下载来说,这是一个非常实用的功能。 CvtCNKI-v2.0.1是软件的...

    C++ Concurrency in Action 完整版

    并发编程是一个广泛的话题,涉及到线程的创建、管理、数据共享、同步、内存模型、设计无锁数据结构、设计基于锁的数据结构、并发代码设计、高级线程管理和多线程应用程序的测试与调试等多个方面。 在描述中,书籍的...

    电子阅读器修正版

    在IT行业中,电子阅读器是一种专门用于阅读电子书的软件或设备,它们通常具有文本...这个修复过程涉及到了C#中对剪贴板的操作、可能的多线程同步问题以及异常处理策略,这些都是开发高质量软件时必须考虑的关键因素。

Global site tag (gtag.js) - Google Analytics