java并发与多线程(二):线程安全

线程可以拥有自己的操作栈、程序计数器、局部变量表等资源,它与同一进程内的其他线程共享该进程的所有资源。线程在生命周期内存在多种状态。有NEW(新建状态)、RUNNABLE(就绪状态)、RUNNING(运行状态)、BLOCKED(阻塞状态)、DEAD(终止状态)五中状态。


image.png

(1) New即新建状态

是线程被创建且未启动的状态。创建线程的方式有三种:第一种是继承Thread类,第二种是实现Runnable接口,第三种是实现Callable接口。相比第一种,推荐第二种方式,因为继承自Thread类往往不符合里氏代换原则,而实现Runnable接口可以使编程更加灵活,对外暴露的细节比较少,让使用者专注于实现线程的run()方法上。第三种call()声明如下:


image.png

由此可知,Callable与Runnable有两点不同:第一,可以通过call()获得返回值。前两种方式都有一个共同的缺陷,即在任务执行完成后,无法直接获取执行结果,需要借助共享变量等获取,而Callable和Future则很好地解决了这个问题;第二,call()可以抛出异常。而Runnable只有通过setDefaultUncaughtExceptionHandler()的方式才能在主线程中捕捉到子线程异常。

(2)RUNNABLE,即就绪状态

是调用start()之后运行之前的状态。线程的start()不能被多次调用,否则会抛出IllegalStateException异常。

(3)RUNNING,即运行状态

是run()正在执行时线程的状态。线程可能会由于某些因素而退出RUNNING,如时间、异常、锁、调度等。

(4)BLOCKED,即阻塞状态

进入此状态,有以下情况。
同步阻塞:锁被其他线程占用
主动阻塞:调用Thread()的某些方法,主动让出CPU执行权,比如sleep()、join()等。
等待阻塞:执行了wait()。

(5)DEAD,即终止状态

是run()执行结束,或因异常退出后的状态,此状态不能逆转。

(顺手插一个自己的记录:start()和run()方法的区别:
1、start方法用来启动相应的线程;
2、run方法只是thread的一个普通方法,在主线程里执行;
3、需要并行处理的代码放在run方法中,start方法启动线程后自动调用run方法;
4、run方法必去是public的访问权限,返回类型为void。)

线程安全问题只在多线程环境下才出现,单线程串行执行不存在此问题。保证并发场景下的线程安全,可以从以下四个维度考量:

(1)数据单线程可见。

单线程总是安全的。通过限制数据仅在单线程内可见,可以避免数据被其他线程篡改。最典型的就是线程局部变量,它存储在独立虚拟机栈帧变量表中,与其他线程毫无瓜葛。ThreadLocal就是采用这种方式来实现线程安全的。

(2)只读对象。

只读对象总是安全的。他的特性是允许复制、拒绝写入。最典型的只读对象有String、Integer等。一个对象想要拒绝任何写入,必须要满足以下条件:使用final关键字修饰类,避免被继承;使用private final关键字避免属性被中途修改;没有任何更新方法;返回值不能可变对象为引用。

(3)线程安全类。

某些线程安全类的内部有非常明确的线程安全机制。比如Stringbuffer就是一个线程安全类,它采用synchronized关键字来修饰相关方法。

(4)同步与锁机制。

如果想要对某个对象进行并发更新操作,但又不属于上述三类,需要开发工程师在代码中实现安全的同步机制。虽然这个机制支持的并发场景很有价值,但非常复杂且容易出现问题。

线程的安全核心理念就是“要么只读,要么加锁”。合理利用好JDK提供的并发包,往往能化腐朽为神奇。Java并发包(java.util.concurrent, JUC)中大多数类注释都写有:@author Doug Lea。如果说Java是一本史书,那么Doug Lea绝对是开疆拓土的伟大人物。Doug Lea在大学当老师时,专攻并发编程和并发数据结构设计,主导设计了JUC并发包,提高了Java并发编程的易用性,大大推进了Java的商用进程。并发包主要分成以下几个类族:

(1)线程同步类。

这些类使线程间的协调更加容易,支持了更加丰富的线程协调场景,逐步淘汰了使用Object的wait()和notify()进行同步的方式。主要代表为CountDownLatch、Semaphore、CyclicBarrier等。

(2)并发集合类。

集合并发操作的要求是执行速度快,提取数据准。最著名的类非ConcurrentHas和Map莫属,它不断地优化,由刚开始的锁分段到后来的CAS,不断地提升并发性能。其他还有ConcurrentSkipListMap、CopyOnWriterArrayList、BlockingQueue等。

(3)线程管理类。

虽然Thread和ThreadLocal在JDK1.0就已经引入,但是真正把Thread发扬光大的是线程池。根据实际场景的需要,提供了多重创建线程池的快捷方式,如使用Executors静态工厂或者使用ThreadPoolExecutor等。另外,通过ScheduledExectorService来执行定时任务。

(4)锁相关类。

锁以Lock接口为核心,派生出一些在实际场景中进行互在斥操作的锁相关类。最有名的是ReentrantLock。锁的很多概念在弱化,是因为锁的实现在各种场景中已经通过类库封装进去了。

并发包中的类族有很多,差异比较微妙,开发工程师需要有很好的Java基础、逻辑思维能力,还需要有一定的数据结构基础,才能够彻底分清各个类族的优点、缺点及差异点。
解决线程安全问题的能力时开发工程师进阶的重要能力之一。由于初创公司的业务流量通常比较小,再加上其初级程序员缺乏线程安全意识。所以,即使出现了由高并发导致的错误,往往也由于复现难度大、追踪困难而不了了之。但是在后期的系统重构中,这些公司一定会为以上线程安全隐患买单。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343