多线程编程的目标与挑战

1、并行和并发

  • 并发:一段时间内交替完成多个任务
  • 并行:以齐头并进方式完成多个任务

并发的极致就是并行

2、多线程的实质是将任务的处理方式由串行改为并发

3、竞态

  • 定义:计算的正确性依赖于相对时间顺序或者线程交错
  • 不一定会导致计算结果不正确,只是不排除计算结果时而正确时而错误的可能
  • 竞态往往伴随读取脏数据问题
  • 局部变量不会导致竞态

4、线程安全性

  • 线程安全:一个类在单线程环境下运作正常,在多线程环境下使用者不必为其做任何改变的情况下也能运作正常
  • 非线程安全:单线程下正常多线程下不正常

5、线程安全问题

  • 原子性

1、“不可分割”其一:访问(读、写)某个共享变量的操作从其执行线程以外的任何线程来看,该操作要么已经执行结束要么尚未发生,即其他线程不会“看到”该操作执行了部分的中间效果
2、“不可分割”其二:访问同一组共享变量的原子操作是不能够被交错的
3、Java实现原子性的两种方式:使用锁Lock;利用处理器提供的专门CAS指令
4、Java语言中,long型和double型以外的任何类型的变量的写操作都是原子操作,volatile关键字修饰的long/double型变量的写操作有原子性
5、原子操作+原子操作所得到的复合操作并非原子操作

  • 可见性

1、定义:一个线程对共享变量的更新结果对于读取相应共享变量的线程而言是否可见的问题
2、可见性问题的产生:
线程运行在不同的处理器,共享的变量分配在寄存器上,因为一个处理器的寄存器无法读取另一个处理器的寄存器上的内容
3、缓存同步使得一个处理器上的线程可以读取到另一个处理器上线程对共享变量所做的更新,即保障了可见性
4、可见性通过是更新共享变量的处理器执行冲刷处理器缓存的动作,并使读取共享变量的处理器执行刷新处理器缓存的动作来实现
5、父线程在启动子线程之前对共享变量的更新对于子线程是可见的;一个线程终止后该线程对共享变量的更新对于调用该线程的join方法的线程是可见的

  • 有序性

1、重排序:对内存访问有关的操作(读和写)所做的优化
2、指令重排序:源代码顺序与程序顺序不一致,或者程序顺序与执行顺序不一致的情况下发生
3、重排序a可能导致线程安全问题;b不是必然出现

  • 上下文切换:一个线程被暂停另一个线程被选中开始

猜你喜欢

转载自blog.csdn.net/yhq9494/article/details/86347716