并行与并发:
并行:在同一时刻同时进行.
并发:在同一时间段内同时进行.
进程与线程:
**进程:**正在运行的程序.
**线程:**进程中完成某一个特定功能的执行单元.
每个进程拥有独立的堆和栈.
每个线程拥有独立的栈,堆是共享的.
**线程调度:**cpu在多个线程中快速切换(纳秒级别的).
线程调度分为两种:
分时调度:每个线程平均分配CPU的执行时间
抢占式调用:每个线程随机分配CPU的时间,具体的随机概率和优先级有关
优先级越高的抢到CPU的概率越高
Java采用抢占式调度,Java程序运行时,默认至少有三个线程
a.main方法所在的线程,我们称为主线程
b.垃圾回收器所在的线程,垃圾回收线程
c.异常打印时也是一个线程,异常线程
创建多线程的两种方式:
方式一:
-
编写一个类继承Thread类,重写其中的run方法.
-
创建子类的对象,调用start方法开启线程.
方式二: -
编写一个类实现runnble接口,重写其中的run方法
-
创建实现类对象,调用start方法开启线程.
我们认为实现方式比较好!!! a.继承方式只能单继承,实现方式弥补单继承的不足 b.继承方式线程对象和任务对象是紧紧耦合的,而实现方式线程对象和任务对象是解耦合的 c.以后我们用的线程池,我们提交时只能提交任务对象(Runnable/Callable),不能提交线程对象 总结:JDK强烈建议,尽量使用实现类方式创建线程
三种线程同步的方式:
a.同步代码块(最常用的方式)
格式:
synchronized(锁对象){
需要同步的那些代码
}
锁对象:可以是任意对象,但是必须是同一个对象
b.同步方法
格式:
public synchronized void method(){
需要同步的那些代码
}
同步方法也是需要锁对象的,但是锁对象不需要我们提供,默认使用this
如果同步方式是静态的,那么也需要锁,默认使用当前类的字节码文件
c.Lock锁
格式:
Lock lock = new ReentrantLock();
lock.lock();
需要同步的那些代码
lock.unlock();
线程的六种状态:
a.新建状态(New)
刚刚创建,但是没有启动的线程
b.可运行状态(Runnable)
新建状态的线程,调用了启动方法
c.锁阻塞状态(Blocked)
当前需要锁,但是锁被其他线程持有
d.限时等待状态(Timed_waiting)
在线程中调用Thread.sleep(毫秒值)
e.无限等待状态(Waiting)
i.线程如何进入Waiting(无线等待状态)
a.当前线程必须先持有锁对象
b.调用锁对象的wait()方法 -- 线程就可以进入无限等待了
c.当前线程进入无限等待之前,先自动释放锁对象
ii.其他线程如何唤醒Waiting状态的线程
a.其他线程也需要持有锁(必须和无限等待线程释放的锁是同一个锁对象)
b.调用锁对象的notify()方法 -- 唤醒无限等待中的那个线程
c.被唤醒线程会进入锁阻塞状态,直到再次持有同一个锁对象,才可进入运行状态
f.消亡状态(Terminated)
当线程的任务执行完毕