多线程
进程与线程
- 进程: 是程序运行和资源分配的基本单位,一个程序至少有一个进程,一个进程至少有一个线程。
- 线程: 是程序执行的最小单元,多个线程可共享进程的资源。线程直接切换效率更高,更节省系统资源。
线程是并发编程的基础,使用它可以有效的提高程序整体的运行速度。
创建线程的方式
- 继承Thread类重写run方法。然后,
new MyThread().start()
,启动线程。
class MyThread extends Thread{
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
}
}
- 实现Runnable接口并实现run方法,创建其实例作为参数传给Thread执行线程任务。
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
}
}).start();
线程的生命周期
线程的生命周期包含5个阶段:新建、就绪、运行、阻塞、销毁。
- 新建:就是刚使用new方法,new出来的线程。
- 就绪:就是调用的线程的start()方法后,这时候线程处于等待CPU分配资源阶段,谁先抢的CPU资源,谁开始执行。
- 运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态,run方法定义了线程的操作和功能。
- 阻塞:在运行状态的时候,可能因为某些原因导致运行状态的线程变成了阻塞状态,比如sleep()、wait()之后线程就处于了阻塞状态,这个时候需要其他机制将处于阻塞状态的线程唤醒,比如调用notify或者notifyAll()方法。唤醒的线程不会立刻执行run方法,它们要再次等待CPU分配资源进入运行状态。
- 销毁:如果线程正常执行完毕后或线程被提前强制性的终止或出现异常导致结束,那么线程就要被销毁,释放资源。
线程的状态
- 线程的状态在 JDK1.5 之后以枚举的方式被定义在Thread的源码中。包含以下六个状态。
public enum State {
/**
* 新建状态,线程被创建出来,但尚未启动时的线程状态
*/
NEW,
/**
* 就绪状态,表示可以运行的线程状态,但它在排队等待来自操作系统的 CPU 资源
*/
RUNNABLE,
/**
* 阻塞等待锁的线程状态,表示正在处于阻塞状态的线程
* 正在等待监视器锁,比如等待执行 synchronized 代码块或者
* 使用 synchronized 标记的方法
*/
BLOCKED,
/**
* 等待状态,一个处于等待状态的线程正在等待另一个线程执行某个特定的动作。
* 例如,一个线程调用了 Object.wait() 它在等待另一个线程调用
* Object.notify() 或 Object.notifyAll()
*/
WAITING,
/**
* 计时等待状态,和等待状态 (WAITING) 类似,只是多了超时时间,比如
* 调用了有超时时间设置的方法 Object.wait(long timeout) 和
* Thread.join(long timeout) 就会进入此状态
*/
TIMED_WAITING,
/**
* 终止状态,表示线程已经执行完成
*/
TERMINATED;
}
相关方法
- join: 当前线程会让出CPU的时间片给新加入的线程,直到其执行完毕或者过了超时时间,才会继续执行当前线程。
- sleep: Thread的静态方法,使当前线程以指定的毫秒数暂停执行。对象的机锁没被释放。
- start: 使此线程处于就绪状态,等待CPU时间片的分配,然后JVM会调用线程的run方法。
- yield: 给线程调度器一个暗示表示愿意让出CPU的使用权,但线程调度器可能会忽略这个暗示。不稳定。
- wait: wait()是Object类的方法,当一个线程执行到wait方法时,它就进入到一个和该对象相关的等待池,同时释放对象的机锁,使得其他线程能够访问,可以通过notify,notifyAll方法来唤醒等待的线程。
- notify: 当有线程调用某对象的notify方法,被唤醒的对象进入对象的锁池里去竞争对象锁。
- notifyAll: 将该对象等待池的所有线程移入锁池共同竞争对象锁 。