基本知识
在多核的CPU中,一个CPU(核心),一个核心基本可以运行多个线程,每个执行一段时间切换到下一个线程,但是如果线程过多就会产生 切换上下文的时间消耗,所以线程不能过多。由于现在CPU执行速度过快,内存极大的拖慢了速度,所以在CPU中会有L1、L2、L3的缓存,速度极快,用于充当CPU和内存的桥梁提高速度
CPU多级缓存
由于每个CPU都有自己的缓存区,为了保证多个CPU缓存区域使用到共享数据如何保证数据的一致性,就出现了MESI
的协议
M(修改):当前CPU缓存独占且已修改了共享数据,即与主存的数据不一致,需要被写回主内存,当写回主存以后变为E状态
E(独享):一个CPU缓存独占数据且和主存中的一致,当被读取时进入S状态,当被修改时进入M状态
S(共享): 该缓存与主存中的数据一致,可能被多个CPU缓存,当其中cpu对数据做出修改时,其他cpu缓存的该数据可以进入I(无效)状态
I(无效):缓存无效,其他cpu修改了共享数据
除了I状态,其他状态都可以被读取,写请求只能在M状态或者是E状态下可以被写入,如果处于S必须将其他cpu中的数据变为I状态才可写入
CPU优化
CPU可能会为了提高运算速度而调整代码原有顺序,但是会保证结果一致,但是多核环境下不一定,因为多核运行可能第一个依赖第二个核的线程的结果在做操作,但是结果CPU优化把第一个CPU的代码先运行就会造成某些意料之外的结果
使用多处理器
如果使用一个双处理器中运行一个单线程程序,等于放弃了其中一半的资源,其实单个处理器也能运行多线程程序,如果一个线程是单线程的,在这个处理器等待同步IO时,处理器依旧是空闲状态,如果使用程序多线程,当程序遇到阻塞时,另外一个线程也能执行
使用多线程的好处
多线程毋庸置疑的,在把多个任务分给多个线程,能提高其效率,但是如果创建过多的线程可能反而会降低效率, 因为过多的线程会引起上下文切换,因为处理器在执行的时候是分时执行,需要在不同的线程中来回切换,这就导致了大量时间消耗
线程安全举例
在我们常用的servlet中,在客户端发送请求过来时,都是多线程访问servlet,但是我们好像重来没有关注过它,那么它们是线程安全的吗,如下,她是线程安全的,因为它是一个无状态类,每一个线程进入以后,都会新建那些变量,对象之间没有共享状态,故而是安全的
下面这个servlet是线程不安全的,因为它们访问了类变量,类变量是对象之间共享的,也就是线程之间共享的,多个线程操作同一个共享变量就会造成线程安全问题,因为
i++
并不是一个原子性操作,它的操作可以被分解为三个步骤,取出i,i+1,赋值给i,多个线程运行时,可能阻塞在其中一步,就运行其他线程,导致的结果就是多个线程修改后的变量结果一致竞争条件和数据竞争
竞争条件
:指的是当一个线程在执行一个判断语句为真,然后阻塞去执行线程2,线程2把判断语句里的指值更新到了false,这是线程1就会出现预料之外的问题,例如懒汉式单例就存在竞争条件
数据竞争
:上面那个线程非安全的举例就是数据竞争,由于没有对共享变量做同步处理,多个线程访问时,可能在去读到还未修改时,另外一个线程也在读取修改
原子性
有线程A和B,当线程B在执行多个操作时,必须保证这个B的操作要么同时操作,要么不操作