多线程
1、线程和进程:
操作系统一般都支持同时运行多个任务,一个任务通常是一个程序,每个运行中的程序就是一个进程。当一个程序运行时,内部可能包含多个顺序执行流,每个顺序执行流就是一个线程。
进程是处于运行过程中的程序,并且具有一定的独立功能,是系统进行资源分配和调度的一个独立单位。
线程是进程的执行单元,线程在程序中是独立的、并发的执行流。多个线程间共享进程资源。
并发性:并发指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行
并行性:并行指在同一时刻,有多条指令在多个处理器上同时执行
2、线程的创建和启动
1)继承Thread类创建线程类
线程类不能再继承其他父类
1 public class FirstThread extends Thread { 2 public void run() { 3 for (int i = 0; i < 20; i++) { 4 System.out.println(getName() + " " + i); 5 } 6 } 7 8 public static void main(String[] args) { 9 for (int i = 0; i < 20; i++) { 10 System.out.println(Thread.currentThread().getName() + " " + i); 11 if (i == 4) { 12 new FirstThread().start(); 13 new FirstThread().start(); 14 } 15 } 16 } 17 }
2)实现Runnable接口创建线程类
线程类可以继承其他类,多个线程共享一个target对象,适合多个相同线程处理同一份资源
1 public class SecondThread implements Runnable{ 2 public void run() { 3 for (int i = 0; i < 20; i++) { 4 System.out.println(Thread.currentThread().getName() + " " + i); 5 } 6 } 7 8 public static void main(String[] args) { 9 for (int i = 0; i < 20; i++) { 10 System.out.println(Thread.currentThread().getName() + " " + i); 11 if (i == 4) { 12 SecondThread secondThread=new SecondThread(); 13 new Thread(secondThread,"新线程1").start(); 14 new Thread(secondThread,"新线程2").start(); 15 } 16 } 17 } 18 }
3、生命周期
1)当使用new关键字创建一个线程后,该线程处于新建状态,此时仅仅有Java虚拟机为其分配了内存,并初始化成员变量的值。
2)当线程对象调用start()后,该线程处于就绪状态,Java虚拟机会为其创建方法调用栈和程序计数器,但并没有开始运行,何时运行取决于JVM里线程调度器的调度
3)如果就绪状态的线程获得CPU,开始执行run方法的线程执行体,处于运行状态。如果计算机只有一个CPU,在任何时刻只有一条线程处于运行状态,在一个多处理器的机器上,将会有多个线程并行执行,当线程数大于处理器数时,依然会有多条线程在同一个CPU上轮换
(调用yield()可以让当前处于运行状态的线程进入就绪状态)
4)下面几种情况,线程会进入阻塞状态:
(1)线程调用sleep方法主动放弃所占用的处理器资源
(2)线程调用了一个阻塞式IO方法,在该方法返回前该线程被阻塞
(3)线程试图获得一个同步监视器,但该同步监视器正被其他线程所持有
(4)线程在等待某个通知(notify)
(5)程序调用了线程的suspend方法将该线程挂起,此方法易导致死锁
5)下面情况线程会接触阻塞重新进入就绪状态:
(1)调用sleep方法的线程经过了指定时间
(2)线程调用的阻塞式IO方法已经返回
(3)成功获得同步监视器
(4)其他线程发出了等待的通知
(5)挂起的线程被调用了resume恢复方法
6)以下方式会处于死亡状态
(1)run()方法执行完成,线程正常结束
(2)线程抛出一个未捕获的Exception或Error
(3)直接调用该线程的stop()方法来结束该线程--易导致死锁,少用
不要对处于死亡状态的线程调用start()方法,程序只能对新建状态的线程调用start()方法,对新建状态的线程两次调用start()方法也是错误的