Java concurrent in practice是一本好书,不过太繁冗.本文主要简述第一部分的内容。

多线程

优势

  • 与单线程相比,可以利用多核的能力;
  • 可以方便的建模成一个线程处理一种任务;
  • 与异步模型相比,多线程同步模型更简单;
  • 通过分离界面线程和工作线程, 可用于创建灵敏的用户界面.

劣势

  • 多线程模型下,对象的状态不在受顺序执行的安全保护,而是需要同步.
  • 同步下可能会出现不一致的问题,如死锁,饥饿.
  • 多线程上下文切换开销可能会导致性能下降.

线程安全和同步

线程安全就是正确的同步状态,包括以下几种方式:

- 无状态(把对象定义成不可变(immutable))

- 不共享状态(通过线程封闭技术)

- 在访问状态变量时使用同步机制.(如对象内部锁的synchronized关键字)

同步机制的目标是实现原子性,避免竞争条件.

- 原子性是一个操作只会一次性完成, 完成前不会被打断.系统有些操作是原子性,它属于内存模型的一部分,另一些对象也可以实现原子操作,它属于同步机制.

- 常见的竞争条件包括:读取-修改-写入,先检查后执行.大多数可以分成读写两步或以上的操作都是竞争条件.

- 最基本的同步机制是加锁,即使用synchronized关键字.把一组可能的竞争条件放到同步机制.读写都需要加锁.注意同一个竞争条件的锁需要一致.

性能

加锁同步可能导致性能下降,需要在线程安全的情况下,尽量小的范围加锁可以用小范围的多次加锁取代一次大范围加锁.特别是费时操作不应在有锁的情况下进行.

** 使用其它同步机制可以提高性能.

线程间状态共享

对象的状态应在对象可控的范围内维护,如果超出了这个范围,即是逸出(Escape).实践上,对象状态应通过方法来访问和修改,如果直接返回对象内部的引用,很可能是逸出.

特别地:

1. 内部类可以隐含的逸出this对象.

2. 构造函数中传出this引用可能逸出,

因为this可能还不完整.

为了安全的共享状态,可以把对象定义成不变类或事实不变类,也可以用线程封闭技术.

线程封闭

线程封闭是不共享状态的一种特例,状态只在一个线程中使用,即状态只保存在局部变量或ThreadLocal变量中.

不变类

不可变对象是状态与实例绑定的对象,即实例一但创建它的状态就不再改变.新的状态由一个新的实例来表示.不可变对象要满足以下条件:

1.创建后不能修改,没有公开的修改方法.

2.所有成员变量都是final

3.创建过程中没有传出this指针.

事实不可变对象由一个可变对象管理时,事实不可变对象的引用本身可能是并不安全.因此必须使用线程安全的访问方式.

线程安全的方式

1.静态初始化对象引用.

2.保存为volatile或AtomicReference

3.正确构造的对象的final域.

4.保存在由锁保护的域.

通过组合线程安全的对象来定义新的线程安全对象

组合

组合多个线程安全的对象可能得到一个线程安全的对象,但如果对象的不变式不能满足则需要同步机制来保证.即各组成对象之间不独立,而是一个随另一个变化.

为线程安全的代码添加新功能,最好的办法是组合,并委托,注意不能逸出原来的对象.

基础构造块

1.同步容器,包括Vector/HashTable, Collections.synchronizedXXX.它们都使用内部锁.同步容器在遍历时可能需要加锁,更好的办法是在副本上遍历.

2.并发容器,包括java.utils.concurrent包内,如concurrentHashMap, CopyOnWriteArrayList, BlockingQueue,ConcurrentListedQueue.它们不需要在遍历过程中加锁.

同步工具

  1. CountDownLatch可以用于等待多个事件都发生后,才同时启动所有线程.例如等待所有线程都退出.
  2. FutureTask可用于长期计算.

Java中编写线程安全代码的原理(Java concurrent in practice的快速要点)的更多相关文章

  1. 编写高质量代码:改善Java程序的151个建议(第一章:JAVA开发中通用的方法和准则)

    编写高质量代码:改善Java程序的151个建议(第一章:JAVA开发中通用的方法和准则) 目录 建议1: 不要在常量和变量中出现易混淆的字母 建议2: 莫让常量蜕变成变量 建议3: 三元操作符的类型务 ...

  2. 用代码说话:如何在Java中实现线程

    并发编程是Java语言的重要特性之一,"如何在Java中实现线程"是学习并发编程的入门知识,也是Java工程师面试必备的基础知识.本文从线程说起,然后用代码说明如何在Java中实现 ...

  3. Java中的线程

    http://hi.baidu.com/ochzqvztdbabcir/item/ab9758f9cfab6a5ac9f337d4 相濡以沫 Java语法总结 - 线程 一 提到线程好像是件很麻烦很复 ...

  4. 编写高质量代码:改善Java程序的151个建议(第二章:基本类型)

    编写高质量代码:改善Java程序的151个建议(第二章:基本类型) 目录 建议21:用偶判断,不用奇判断 建议22:用整数类型处理货币 建议23:不要让类型默默转换 建议24:边界还是边界 建议25: ...

  5. JAVA中创建线程的三种方法及比较

    JAVA中创建线程的方式有三种,各有优缺点,具体如下: 一.继承Thread类来创建线程 1.创建一个任务类,继承Thread线程类,因为Thread类已经实现了Runnable接口,然后重写run( ...

  6. Java多线程编程(1)--Java中的线程

    一.程序.进程和线程   程序是一组指令的有序集合,也可以将其通俗地理解为若干行代码.它本身没有任何运行的含义,它只是一个静态的实体,它可能只是一个单纯的文本文件,也有可能是经过编译之后生成的可执行文 ...

  7. java 中创建线程有哪几种方式?

    Java中创建线程主要有三种方式: 一.继承Thread类创建线程类 (1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务.因此把run()方法称为执行 ...

  8. 【万字图文-原创】 | 学会Java中的线程池,这一篇也许就够了!

    碎碎念 关于JDK源码相关的文章这已经是第四篇了,原创不易,粉丝从几十人到昨天的666人,真的很感谢之前帮我转发文章的一些朋友们. 从16年开始写技术文章,到现在博客园已经发表了222篇文章,大多数都 ...

  9. 《Java并发编程的艺术》 第9章 Java中的线程池

    第9章 Java中的线程池 在开发过程中,合理地使用线程池能带来3个好处: 降低资源消耗.通过重复利用已创建的线程 降低线程创建和销毁造成的消耗. 提高响应速度.当任务到达时,任务可以不需要等到线程创 ...

随机推荐

  1. UVA 1493 Draw a Mess(并查集+set)

    这题我一直觉得使用了set这个大杀器就可以很快的过了,但是网上居然有更好的解法,orz... 题意:给你一个最大200行50000列的墙,初始化上面没有颜色,接着在上面可能涂四种类型的形状(填充):  ...

  2. HYSBZ - 1588 splay

    题意:每天给你一个数,要求统计最小波动值,强制在线的就是每次从已经出现过的数值中找与当前值间隔最小的加起来 题解:splay维护,同时求解当前值的前驱和后继,找距离小的那个就好了 splay是一种二叉 ...

  3. 十二 Django框架,自定义分页

    自定义分页模块 #!/usr/bin/env python #coding:utf-8 from django.utils.safestring import mark_safe #封装分页类模块 c ...

  4. png8 png24 png32

    解释 PNG8 : 8位的PNG最多支持256(2的8次方)种颜色,8位的PNG支持不透明.索引透明.alpha透明. PNG24 : 支持2的24次方种颜色,表现为不透明.PS导出PNG24是会根据 ...

  5. QMainFrame类

    一.简介: 1.QMainFrame类提供了应用程序的主窗口,因为它可以添加菜单.工具条.状态栏和停靠窗口,同时也支持单文档窗口和多文档窗口,这是它和其他窗口不一样的地方. 2.QMainFrame窗 ...

  6. Echarts 关系图 添加点击事件

    /*实现的效果是:在关系图上加点击事件,点击某个点,得到改点代表的内容,并且实现一个跳转效果. 关键代码已用红色标出*/ <!DOCTYPE html> <html lang=&qu ...

  7. ffmpeg代码实现自定义encoder

    1.概述 本文主要讲述如何用ffmpeg代码实现自己的encoder. 2.代码 /* *本程序主要实现一个自己的encoder并加入到encoder链中去,供api调用 *作者:缪国凯(MK) *8 ...

  8. redisCheckMem脚本

    最近维护的redis cluster需要扫描每个实例的内存使用率,首先我们需要获取实例已经使用的内存,获取实例的最大内存配额,两个值相比就能获取到内存使用比例. 实例的最大内存获取方法: $REDIS ...

  9. 51Nod1766 树上的最远点对

    1766 树上的最远点对 n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即你需要求出max{dis(i,j) |a<=i&l ...

  10. ACM学习历程—Rotate(HDU 2014 Anshan网赛)(几何)

    Problem Description Noting is more interesting than rotation! Your little sister likes to rotate thi ...