进程和线程
***进程:私有空间,彼此隔离,拥有整台计算机的资源,多进程之间不共享内存,进程之间通过消息传递进行协作
一个应用中可能包含多个进程
***线程:程序内部的控制机制
每个应用至少有一个线程;主线程,可以创建其他的线程
线程的创建和启动,runnable
***创建线程:从Thread类派生子类;从Runnable接口构造Thread对象
内存共享模式、消息传递模式
***内存共享模式
内存之间的共享内存可能会导致微妙的错误
在内存中读写共享数据
两个处理器,共享内存;同一台机器上的两个程序,共享文件系统;同一个Java程序内的两个线程,共享Java对象
***消息传递模式:通过channel 交换
例:同一个Java程序内的两个线程,共享Java对象
浏览器和Web服务器,A请求页面,B发送页面数据给A
同一台计算机上的两个程序,通过管道连接进行通讯
时间分片、交错执行、竞争条件
***时间分片:通过时间分片,在多个进程/线程之间共享处理器
时间分片是由OS 自动调度的
***竞争条件:程序的正确性(满足后置条件和不变量)取决于并发计算A和B中时间的相对时间。有时线程会相互影响
线程干扰!!!
线程的休眠、干扰
***休眠:Thread.sleep(time)
将某个线程休眠,意味着其他线程得到更多的执行机会
进入休眠的线程不会失去对现有monitor或锁的所有权
***干扰:Thread.interrupt()
使用isInterrupted()检查线程是否被中断
当某个线程被中断后,一般来说应停止其run()中的执行,取决于程序员在run()中处理
一般来说,线程在收到中断信号时应该中断,直接终止,但是,线程收到其他线程发来的中断信号,并不意味着一定要“停止”…
线程安全threadsafe的四种策略
***confinement:限制数据共享
将可变数据限制在单一线程内部,避免竞争
不允许任何线程直接读写该数据
核心思想:线程之间不共享mutable数据类型
***Imuutability
使用不可变数据类型和不可变引用,避免多线程之间的race condition
不可变数据通常是线程安全的
如果ADT中使用了beneficent mutation,必须要通过“加锁”机制来保证线程安全
***Threadsafe类型
如果必须要用mutable 的数据类型在多线程之间共享数据,要使用线程安全的数据类型
一般来说,JDK 同时提供两个相同功能的类,一个是threadsafe,另一个不是。原因:threadsafe的类一般性能上受影响
集合类都是线程不安全的(List、Set、Map)
***Synchronization/Lock
synchronizeation:对synchronized的方法,多个线程执行它时不允许interleave ,也就是说 “按原子的串行方式执行”
public static <T> Collection<T> synchronizedCollection(Collection<T>c);
public static <T> Set<T>synchronizedSet(Set<T> s);
public static <T> List<T>synchronizedList(List<T> list);
public static <K,V> Map<K,V>synchronizedMap(Map<K,V> m);
public static <T> SortedSet<T>synchronizedSortedSet(SortedSet<T> s);
public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m);
Lock机制:使用锁机制,获得对数据的独家mutation权,其他线程被阻塞,不得访问
Lock 是Java语言提供的内嵌机制:synchronized(lock)
Lock 保护共享数据
要互斥,必须使用同一个lock 进行保护
***死锁:多个线程竞争lock,相互等待对方释放lock
以注释的形式撰写线程安全策略
该ADT 采取了什么设计决策来保证线程安全
多线程之间基于消息传递的实现机制,如何保证threadsafe