线程同步(通信)

2018-05-31  本文已影响0人  哓晓的故事

线程分类

普通线程:主线程创建的所有子线程都是普通线程
守护线程:JVM停止时,抛弃所有守护线程,不执行finally代码块,也不会回收栈

synchronozied

同步方法、同步代码块必须获取对应的监视器monitor
线程之间的相互唤醒属于内存通信机制,Java中使用notify和wait来实现,并且必须在synchronized语句块内使用

注意: 启动一个线程,应该给线程命名,方便监控和排查问题

condition

由于 wait/notify/notifyAll 必须依赖 synchronized,太重不方便使用
可以使用ReentrantLock的condition,一个锁可以创建多个通信condition

ConditionObject 和 Object 通信方式
wait=await
notify=signal
notifyAll=signalAll

一个 ReentrantLock 可以有多个 ConditionObject
而 synchronized 把 lock 和 condition合并了,一个sync只对应一个condition
并且不要在lock/condition`上使用 wait/notify/notifyAll

wait 与 sleep

Thread.sleep()与Object.wait()二者都可以暂停当前线程释放CPU控制权,主要的区别在于wait()在释放CPU同时,释放了对象锁(监控器monitor)的控制

未取得锁(必须是synchronized,ReentrantLock也不行)就直接执行wait、notfiy、notifyAll会抛异常

等待队列condition - 监视器monitor

关键点是条件谓词,条件谓词涉及状态变量,状态变量由保护,所以在测试条件谓词需要先持有
永远在循环中使用wait/await,并且条件是条件谓语,且条件谓词的状态变量保护

每个Java对象有一个监视器monitor,实现了同步队列等待队列,且二者是相关的, 区别是 sync 的队列是放在 monitorobject header 中.

参考 reetrantLock 原理, 使用 同步队列等待队列 来实现.

监视器.png
lock-monitor.png
每个Object或者Class都拥有一个monitor
monitor保证每次只能有一个线程能进入这个房间进行访问被保护的数据
进入房间即为acquire monitor
退出房间即为release monitor
否则进入entry set/wait set队列等待抢占资源
这个队列不是真正的排序,而是唤醒所有等待的线程竞争资源(因为是非公平的)

notify/notifyAll

notify 只会唤起一个wait线程,如果存在多个谓词,存在丢失通知信号的问题,如果只有一个条件谓词,性能足够好。如果Lock的条件队列condition有多个,可以使用notify,(但是notify并不会立即释放monitor,而是等同步块结束才释放

notifyAll 会唤起所有的wait线程,性能不足够好,但是能兼容多个谓词的情况,synchronized的条件队列condition只有一个,但是谓词却又多个,建议使用notifyAll

notify/notifyAll的时候,没有wait的线程,信号就丢失了

interrupt()

线程没有直接终止方法
线程中断的协作机制,协作更合理,留给线程停下手中的动作,然后再终止
修改线程中断状态 -> 表示当前线程应该停止运行,但是当前线程不会立即停止

Thread.sleep();
Thread.join();
Object.wait();

以上动作在监听线程状态位被置为中断,会立即抛出InterruptedException异常
程序应该对线程中断做出响应Thread.interrupted()方法来判断当前线程状态是否被设置为中断状态但是,interrupted()会清空线程的中断状态,除非想ignored这个中断,否则就需要捕获InterrupedException处理或者使用.interrupt()向上反馈中断

异常的线程终止

  1. 非interruped的异常,导致线程中断,在ThreadPool的处理方式是重建一个线程

阻塞队列 BlockingQueue

生产者/消费者 模式中大量使用
take() 如果队列空,会阻塞直到队列有值
put()如果队列满,会阻塞直到队列有空间
offer()如果队列满,会快速返回失败状态

共享变量

1. 线程封闭

  1. ad-hoc
  2. 栈限制,只在栈内生成对象,不对外逃逸
  3. 使用threadLocal

2. 线程不可变

  1. final
上一篇 下一篇

猜你喜欢

热点阅读