多线程总结

线程基础

线程的状态

根据java官方的定义,线程一共有五种状态NEW、RUNNABLE、BLOCKED、WAITING、TIME_WAITING、TERMINATED。需要注意的是:

  • 其中RUNNABLE表示将运行和就需两个状态合并成一个状态。
  • BLOCKED状态是指线程在进入synchronized代码块/方法时等待获取锁时的状态。
  • WAITING状态是因为调用了Object.wait()、Thread.join()、LockSupport.park()


    线程状态

线程的方法

  • Thread.yield() 让出时间片,放弃cpu执行权。让线程处于ready,所以有可能会立即获得cpu的执行权。同时与sleep一样并不会释放锁。

  • Thread.sleep(0),释放cpu时间片,让线程马上回到就绪队列而非等待队列。通过释放当前线程锁剩余的时间片,从而达到让操作系统来执行其他线程,提升效率。

  • Thread.join() 在Main线程中调用了t.join()方法,会使t线程执行完Main线程才会继续往下走,内部通过wait()实现。

sleep和wait的区别

  • sleep是Thread的方法
  • wait是Object的方法
  • sleep不会释放锁
  • wait会释放锁 然后会将锁加到对象监视器的等待队列中去
  • 因此wait必须要在同步方法/同步代码块中使用,而sleep则不需要
  • 被wait的同步方法/同步代码块必须要由notify来唤醒

多线程运行时捕获线程异常

线程安全

同步容器

  • Vector、Stack
  • HahsTable
  • Collections.synchronizedXXX(List,Set,Map)

并发容器

  • CopyOnWriteArrayList
    在每次修改时,都会创建并重新发布一个新的容器副本,从而实现可变性。CopyOnWriteArrayList的迭代器保留一个指向底层基础数组的引用,这个数组当前位于迭代器的起始位置,由于它不会被修改,因此在对其进行同步时只需确保数组内容的可见性。因此,多个线程可以同时对这个容器进行迭代,而不会彼此干扰或者与修改容器的线程相互干扰。“写时复制”容器返回的迭代器不会抛出ConcurrentModificationException并且返回的元素与迭代器创建时的元素完全一致,而不必考虑之后修改操作所带来的影响。显然,每当修改容器时都会复制底层数组,这需要一定的开销,特别是当容器的规模较大时,仅当迭代操作远远多于修改操作时,才应该使用“写入时赋值”容器。
  • CopyOnWriteArraySet ConcurrentSkipListSet
  • ConcurrentHashMap ConcurrentSkipListMap
    (SkipListXXX 表示有序)

同步

使用synchronized关键字

  • synchronized用在方法上使用ACC_SYNCHRONIZED来完成
  • synchronized用在代码块上是用monitorenter 和 monitorexit指令
  • 其实本质都是对一个对象的监视器进行获取
  • jdk1.6的优化在于将锁升级成偏向锁->轻量级锁->重量级锁

ReentrantLock

公平锁和非公平锁的区别

  • 非公平锁在调用lock后,会立即进行一次CAS抢锁,如果锁没有被占用,泽直接获取锁并返回。
  • 如果非公平锁CAS失败了,会和公平锁一样进入tryAcquire,在tryAcquire方法中如果发现锁被释放(state==0),非公平锁会直接CAS抢锁,但是公平锁会判断锁wait set是否有线程等待,如果有则进行排队
  • 以上两点就是它们的区别,所以实际上如果非公平锁两次CAS都不成功,那么后面和公平锁一样进入阻塞队列等待唤醒。所以非公平锁拥有更好的性能,因为他的吞吐量大,但是他也有可能让获取锁的时间不确定从而导致阻塞队列的线程线程饥饿。

ReentrantLock和synchronized的区别

  • ReentrantLock提供中断的获取锁
  • ReentrantLock提供尝试的获取锁
  • ReentrantLock提供超时的获取锁
  • ReentrantLock提供公平的获取锁
  • ReentrantLock提供同时绑定多个Condition对象,而在synchronized中,锁对象的wait、notify、notifyAll方法可以实现一个隐含条件,如果要和多于一个的条件关联的对象,就不得不额外的添加一个锁,而ReentrantLock则只需要newCondition即可。

阻塞队列BlockingQueue

方法 抛出异常 返回特殊值 可能阻塞等待 可设定等待时间
入队 add(e) offer(e) put(e) offer(e,timeout,unit)
出队 remove() poll() take poll(timeout,unit)
查看 element() peek()

线程池

  • new Thread的弊端
  1. 每次通过new创建线程,性能差
  2. 缺乏统一管理,如果无限制创建线程,会导致占用过多系统资源从而发生死机或者OOM
  3. 缺乏灵活性,比如定期执行、线程中断等特性
  • 线程池的优势
  1. 线程复用,减少开销
  2. 有效控制并发线程数量,提高系统资源利用率,避免过多资源竞争,避免阻塞
  3. 提供定时执行、定期执行、单线程、并发数控制等功能
  • 线程池的生命周期
线程池的生命周期.png
  • shutdown 和 shutdownNow()
  1. shutdown() 当线程池调用该方法时,线程池的状态则立刻变成SHUTDOWN状态。此时,则不能再往线程池中添加任何任务,否则将会抛出RejectedExecutionException异常。但是,此时线程池不会立刻退出,直到添加到线程池中的任务都已经处理完成,才会退出。
  2. shutdownNow() 执行该方法,线程池的状态立刻变成STOP状态,并试图停止所有正在执行的线程,不再处理还在池队列中等待的任务,当然,它会返回那些未执行的任务。它试图终止线程的方法是通过调用Thread.interrupt()方法来实现的,但是大家知道,这种方法的作用有限,如果线程中没有sleep 、wait、Condition、定时锁等应用, interrupt()方法是无法中断当前的线程的。所以,shutdownNow()并不代表线程池就一定立即就能退出,它可能必须要等待所有正在执行的任务都执行完成了才能退出。
  • 合理配置线程池大小
  1. CPU密集型任务,尽量充分利用CPU,设置成 CPU核数+1
  2. IO密集型任务,参考值2*CPU核数

死锁

死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,他们都将无法推进下去。这是一个严重的问题,因为死锁会让你的程序挂起无法完成任务,死锁的发生必须满足以下4个条件:

  • 互斥条件:一个资源每次只能被一个进程使用。
  • 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
  • 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺。
  • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

避免死锁最简单的方法就是阻止循环等待条件,将系统中所有的资源设置标志位、排序,规定所有的进程申请资源必须以一定的顺序做操作来避免死锁。
支持定时的锁 boolean tryLock(long timeout, TimeUnit unit)
通过ThreadDump来分析找出死锁

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

推荐阅读更多精彩内容