《java并发编程实战》1-2章介绍

摘要:这个算是给大家多线程开个门了,后续章节会慢慢更新的。二刷这本神书,带着仰慕的心情读着pdf,回头买个正版支持下!

一、线程优势

1.这个我就不多废话了,总结就是一句话,线程可以利用多处理器的优势,现在处理器那么多,如果有100个处理器,单线程就会损失99%的性能,不利于发挥计算机优势,和资源利用率。同时对于,需要处理Servlet连接的服务器,如果只是单线程,会造成阻塞,与原本的设计理念不符。此外,现在IO操作,包括系统IO操作,和网络IO操作都是非常费时的,如果总是阻塞,系统利用率太差

二、线程风险

对于普通的的程序,思考下面的程序

《java并发编程实战》1-2章介绍    

这个程序看似只有一个语句 value++ , 但是其中包含了三个操作,获取value值,value+1,结果写回value。三个操作会有以下几个问题,(1)两个一起读取value,同时++,结果导致,value值只是+1 (2)一个线程在获取value值前检查了 没有其他线程,但是在value+1时候,另一个线程获取值。所谓的更新前检查,也是不行。

怎么解决这个问题呢? 很显然如果保证 这三个操作只能由一个线程处理就好了,如果同时有线程执行操作必须阻塞。

由此引发了线程的几个问题,活跃性问题,比如死锁,就是一个操作可能永远执行不了。性能问题,同步带来的开销

三、线程无处不在

  JVM本质就是会在后台开启垃圾回收和守护线程。

四、线程介绍

无状态线程就是线程的操作,不包括修改,更新操作,只是单纯的读取一个数值。这种线程肯定是安全的,我们可以将变量设置为final,来保证没有修改操作。

竞态条件:如果计算正确性只存在于线程交替执行,那么这就是不安全的,此线程存在竞态条件。一般存在于先检查后执行操作,需要先获取值才能修改,这就会发生错误。比如你在A处,你朋友在B处。你再A处没发现你朋友,于是你准备去B找他此时1.如果你朋友在B处的状态不会变化,那么你们会最终相遇 2.如果你朋友也去A找你,这个时候就会发生死循环,也就是状态不是你当初检查的状态了。也即是可能失效的观察结果,也就是在检查和执行的过程中,状态改变了

延迟加载也会出现这种问题:

《java并发编程实战》1-2章介绍

  在创建的过程中,另外一个线程也发现instance为null,也创建,就会导致结果不一致。

由此产生了原子类,保证三个操作是一起的,private final AtomicLong  count = new AtomicLont(0);由于AtomicLong是原子操作,也就会保证count值不会被两个线程同时修改,保证了线程安全

五、线程有多个原子操作

《java并发编程实战》1-2章介绍

此代码中,虽然都保证了两个原子类,控制了原子操作。但是如果把两个原子操作放在一起,他俩组合就会发生线程不安全,也就是没法保证组合一起的原子操作是线程安全的。synchronized{} 同步代码块可以保证里面的是原子操作,但是会导致效率,不高。以后会解决这个问题

六、线程的重入

这个是发生在继承阶段,父类的对象锁,子类重载父类的同步方法,同时调用父类的同步锁。这时候就会发现已经获取子类的对象锁,如果锁不可以重入,这时候想获取父类锁就会发现自己已经获取了,没法获取。所以这时候就或锁重入,如果想要获得锁的时候,自己已经获得锁了。就会将计数器+1,最后释放锁是考虑计数器=0? 如果为0,就会释放锁。

七、线程同步代码块使用

下面这个程序是对上图类的改进

《java并发编程实战》1-2章介绍

此程序只在需要的时候使用synchronized,兼顾效率的同时,保证线程安全。这里计数器没有使用Automic包下的类,是因为使用了同步关键字,已经保证了线程安全,如果在使用原子操作,可能会对效率影响。

总结就是,只在需要修改操作的时候,使用同步代码块,其他正常代码允许其他线程访问执行。