一、进程和线程
(1)进程:
计算机在执行的程序的实体,比如. 一个.class文件、 一个.exe文件。
(2)线程:
一个程序内部的顺序控制流。
(3)他们之间的关系:
一个进程中可以包含一个或多个线程,一个线程就是一个程序内部的一条执行线索。
二、多线程的实现方式
1.继承Thread类
通过重写Thread类中的run(),并且调用start()才可启用线程
2.实现Runnable接口
实现Runnable接口,重写其run();
实现Runnable接口的类自己不能启动线程,需要将此类的对象传递给Thread,public Thread(Runnable target){……},由Thread的start方法启动。
通过创建Thread类构造参数中传入Runnable 接口对象,线程可实现对资源的共享,推荐使用此方式。
三、线程状态及生命周期
- 当一个线程执行了start方法后,不代表这个线程就会立即被执行,只代表这个线程处于可运行的状态,最终由OS的线程调度来决定哪个可运行状态下的线程被执行。
- 一个线程一次被选中执行是有时间限制的,这个时间段叫做CPU的时间片,当时间片用完但线程还没有结束时,这个线程又会变为可运行状态,等待OS的再次调度;在运行的线程里执行Thread.yeild()方法同样可以使当前线程变为可运行状态。
- 在一个运行中的线程等待用户输入、调用Thread.sleep()、调用了其他线程的join()方法,则当前线程变为阻塞状态。
阻塞状态的线程用户输入完毕、sleep时间到、join的线程结束,则当前线程由阻塞状态变为可运行状态。 - 运行中的线程调用wait方法,此线程进入等待队列。
- 运行中的线程遇到synchronized同时没有拿到对象的锁标记、等待队列的线程wait时间到、等待队列的线程被notify方法唤醒、有其他线程调用notifyAll方法,则线程变成锁池状态。
- 锁池状态的线程获得对象锁标记,则线程变成可运行状态。
- 运行中的线程run方法执行完毕或main线程结束,则线程运行结束。
四、线程阻塞的原因
1.sleep
2.wait(),知道线程得到了notify()或者notifyAll()消息,线程才会进入就绪状态。
3.任务在等待某个输入/输出完成
4.线程在试图在某个对象上调用其同步控制方法,但是对象锁不可用,因为另一个任务已经获取了这个锁。
五、线程的同步
目的: 有时两个或多个线程可能会试图同时访问一个资源,为了确保在任何时间点一个共享的资源只被一个线程使用,使用了“同步”。
六、同步锁
对象的锁标志
每个对象都有一个锁标志,使用synchronized可与锁标志交互
synchronized关键字的用法有两种:
- synchronized语句:
synchronized (obj){
//在synchronized语句块中
//对obj的成员只能进行同步访问
} - synchronized方法:
一旦一个包含同步方法(用synchronized修饰)的线程被CPU调用,其他线程就无法调用相同对象的同步方法。当一个线程在一个同步方法内部,所有试图调用该方法的同实例的其他线程必须等待
七、死锁
一、死锁的定义
多线程以及多进程改善了系统资源的利用率并提高了系统 的处理能力。然而,并发执行也带来了新的问题——死锁。所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。
二、死锁产生的原因
- 系统资源的竞争
- 进程推进顺序非法