1.线程与进程
进程是操作系统中资源分配的最小单元
线程是操作系统中任务分配的最小单元
创建一个线程的开销要比一个进程小得多,线程间通信比进程间通信容易得多。
线程间通信:join(),wait/notify、yield、sleep
2,多线程常用操作方式
sleep:运行到阻塞,当前线程交出CPU,进入阻塞状态,不会释放对象锁
yield:运行到就绪,系统调度交出CPU,进入就绪状态,不会释放对象锁,只会让相同优先级
的线程获取对象锁。
join:运行到阻塞,进入阻塞态,会释放对象锁。(join内部就是wait方法)。
wait: 运行到阻塞,会释放对象锁,必须与synchronized搭配使用。
notify:从阻塞态返回到就绪态,必须在同步方法或者同步代码块中使用。
用户线程与守护线程。
默认创建的进程都是用户线程:比如主线程
守护线程:在后台执行,只要JVM中存在任意一个用户线程没有终止,守护线程就一直运行。
当JVM最后一个用户线程终止,守护线程随着JVM一起终止。:如GC线程。
3.线程同步与死锁
多线程三个特性(原子性 可见性 有序性)任意一个不满足,都存在线程安全问题。
解决:
3.1 synchronized实现线程安全(必须明白synchronized锁的是谁)
同步代码块
synchronized(锁的对象){}
-普通对象
-类.class
同步方法
-成员同步方法,锁的是当前对象。
-静态同步方法,锁的是类的反射对象。
synchronized底层实现(对象的Monitor机制),任意一个对象都有Monitor,
synchronized对象锁实际上是获取该对象的Monitor。
当前线程想要获取到该锁的Monitor流程:先判断对象Monitor计数器是否为0,
为0表示Monitor还未被任何线程持有,当前线程获取Monitor,并且将持有线程置为自己,
将Monitor计数器值+1。
不为0表示当前Monitor已被线程持有,判断持有线程是否为当前线程,若是,Monitor
计数器值+1。若持有线程不为当前线程,线程进入阻塞状态,等待Monitor的值减到0。
可重入锁:持有锁的线程再次获取锁。