初识并发编程
1. 并发与并行:
1) 并发: 一段时间内能同时处理多个请求
2) 并行: 多个CPU同时去执行
2. 什么时候应该使用多线程:
1) 需要等待网络、I/O响应导致耗费大量的执行时间,而且对实时性要求也不高,可以采用异步线程的方式来减少阻塞
2) 通过并行计算提高程序执行性能
3. 线程状态:
1) new: 线程刚被创建,还没有调用start方法
2) runnable: 获得锁正在执行(running)或准备执行(ready, 由于cpu切换走干别的了)
3) blocked: 没获得到锁,被阻塞
4) waiting: 已经获得锁、正在运行的线程,调用wait, join,park 进入等待, notify,upark从等待状态返回
5) time_waiting: 超时等待,和waiting相比,多一个sleep进入超时等待,多一个超时时间到返回。 wait释放锁,sleep不释放锁
6) terminated: 线程执行完毕
( 针对这个图稍微有一点疑问, 对于Object.wait(),线程会释放锁,那么从waiting状态返回时会先通过cas自选,如果额能获取锁进入runnable状态, 获取不到锁应该进入blocked状态 )
4. 线程的启动:
start是native方法,最终告诉jvm调用run方法
5. 线程的停止:
1) Thread过期的stop,resume, suppend API, 停止线程时,不会释放已经占有的资源,例如锁
2) interrupt方法:
i. 其他线程调用该线程的interrupt方法,设置该线程的中断标志位, 至于什么时候中断,由该线程决定
可以通过isInterrupt判断中断标志位是否被配置,如果配置了将程序暂停
ii. 遇到低优先级的block状态时,比如object.wait(),object.sleep(),object.join()。
interrupt通过 unpark 去唤醒出于waiting状态的线程,并设置中断标识。 wait/sleep/join会throw一个InterruptedException, 抛出异常后,会清除中断标志位
6. 线程安全性问题:
1) JMM:
i. 定义了共享内存系统中多线程程序读写操作行为的规范,来屏蔽各种硬件和操作系统的内存访问差异
ii. 共享变量是指实例对象、静态字段、数组对象等存储在堆内存中的变量。而对于局部变量这类的,属于线程私有,不会被共享 。
2) 线程安全性问题:
i. 可见性:一个线程改变工作内存中的变量,另一个线程立刻可见
ii. 原子性:多线程内自增某一个变量
iii. 有序性: 编译器优化+ 指令重排序, 执行顺序和代码顺序不一致,前提是不影响单线程代码语义,却会影响多线程并发执行的正确性
7. 多线程间的通信:
1) 共享内存:
主内从存放共享变量、多个线程的工作内存会缓存共享变量, 线程对工作内存的修改会同步到主内存中(什么时候同步不一定,会引起可见性问题)
2) 消息传递: wait/notify
8.Thread,Runnable,Callable:
1)Runnable 和Callable是两个接口,分别有run和call两个方法, Runnable方法有返回值, Callable方法没有返回值
2)Thread实现runnable, runnable通过Thread实现多线程,由一个runnable创建的多个Thread间会共享数据。
Thread是对象, runnable接口, runnable可以解决多继承的问题
i. Thread
执行结果如下, 可以看到三个t1,t2,t3 三个线程各卖5张票,三个线程彼此独立
线程t1卖第4张票
线程t1卖第3张票
线程t1卖第2张票
线程t1卖第1张票
线程t3卖第4张票
线程t2卖第4张票
线程t2卖第3张票
线程t2卖第2张票
线程t2卖第1张票
线程t2卖第0张票
线程t3卖第3张票
线程t3卖第2张票
线程t3卖第1张票
线程t3卖第0张票
线程t1卖第0张票
ii. Runable
执行结果如下 ,可以看到Runnable中的count在多个线程中共享,并且出现并发问题:
线程t1卖第3张票
线程t2卖第2张票
线程t2卖第0张票
线程t3卖第3张票
线程t1卖第1张票
现在对为什么Runnable中的count能够在多线程中共享,首先看Thread中的源码,可以看到多个Thread中的target引用同一个Runnable对象,Thread的run方法,最终调用的就是同一个Runnable对象的run方法,所以Runnable中的数据会被共享
iii. Callable:
Callable 可以有返回结果,通过Future或者FutureTask来获得异步执行的结果, FutureTask扩展RunnableFuture, RunableFuture 扩展 Runnable和Future
使用示例如下:
Callable+ Future 最终也是以Callable+FutureTask实现的, executorService.submit(myCallable)的源码如下:
相关源码:https://github.com/925781609/JavaCodeLibary/tree/master/src/main/java/com/liuil/codelibary/multithread