多线程的创建
线程和进程
进程:当一个程序进入内存运行时,即是一条进程。
进程的3个特征:
1. 独立性:进程是系统中的独立实体(包含本身拥有的资源和内存地址)在没有经过本身进程的允许下,一个进程不可以访问其他进程的地址空间。
2. 动态性:进程是一个在内存中活动的指令集。进程具有自己的生命周期。
3. 并发性:多个进程可以在单个cpu上并发执行,多个进程之间不会相互干扰。
线程:线程是进程的组成部分,可以使进程同时执行多个并发的任务。线程必须有一个父进程。
多线程的优势
- 进程之间不能共享内存,但线程之间共享内存很容易。
- 系统创建进程时需要为该线程重新分配系统资源,但线程代价小的多,因此使用多线程实现多任务比多进程的效率高
通过继承Thread类创建线程
- 定义Thread类的子类,并重写该类的run()方法,run()方法中就是该线程需要完成的任务。
- 创建Thread的实例。
调用Thread实例的start()方法。
public class FirstThread extends Thread{ public static void main(String[] args) { //创建Thread实例后调用start()方法启动线程。 new FirstThread().start(); //启动第二个线程 new FirstThread().start(); } //重写run()方法 public void run() { for(int i=0;i<50;i++){ System.out.println(this.getName()+">"+i); } } }
实现Runable接口创建线程类
- 定义实现Runable()接口的类,并重写Run()方法,在run()方法中写需要执行的任务。
- 创建Runable()接口类的实例,并以此实例作为Thread的target来创建Thread对象。Thread才是真正的线程对象,Thred直接执行Runable实例中的run()方法;
调用Thread的start()方法,启动线程;
public class RunnableTest implements Runnable { //实例属性可以在多个线程之间共享 private int i=0 ; @Override public void run() { for(;i<100;i++){ //获得线程名称时不能跟继承Thread方式一样使用this.getName(); //因为这个类不是Thread,只是作为Thread的执行任务。 System.out.println(Thread.currentThread().getName()+">"+i); } }public static void main(String[] args) { //创建实现了Runnable()接口的实例 RunnableTest test = new RunnableTest(); //创建线程1,test作为线程的需要任务 new Thread(test,"thread-1").start() ; //创建线程2,执行的任务与线程1相同 new Thread(test,"thread-2").start() ; } }
采用Runnable接口的形式创建多个线程可以共享线程类的实例属性。因为在这种方式下程序创建的Runnable对象只是线程的Target,而多个线程共享一个Target,这样多个线程就可以共享Runnable对象的实例属性。
上面两种创建线程方式对比
采用实现Runnable()接口的方式创建多线程
- 线程类只是实现了Runnable()接口,还可以继承其他类;
- 在这种方式下,多个线程可以共享一个Target对象,实现数据共享;
- 不过编程相对复杂,访问当前线程时必须使用Thread.currentThread()方法;
采用继承Thread类的方式创建多线程
- 优势:编程简单,本身就是线程类,直接使用this 既可以访问当前线程;
- 缺点:由于已经继承了Thread类,就不能过在继承其他类;
线程的生命周期
线程被创建并启动后,线程并不是一启动就进入执行状态,也不是一直处于执行状态。在线程的生命周期中,线程会经过新建、就绪、运行、阻塞、死亡5种状态。当线程启动后,线程不是一直占用cpu运行,cpu不断切换选择一条线程执行。因此线程状态会多次在运行和阻塞之间切换。
新建和就绪状态
当使用new关键字创建了一个线程之后,该线程就是处于新建状态。java虚拟机会为其分配内存,并初始化成员变量。
当线程对象调用start()方法后,该线程就处于就绪状态。java虚拟机会为其创建方法调用栈和线程计数器,处于就绪状态下的线程是没有开始执行的,只是表示可以执行了。
启动线程使用Start()方法,不是run()方法。调用start()方式启动线程时,系统会将run()方法当成线程要执行的任务处理。而调用run()方法时,系统会将run()方法当成普通的方法立即执行,在run()方法反回之前,其他线程线程无法并发执行。调用run()方法后线程不再是新建状态,不能在调用start()方法
运行和阻塞状态
当处于就绪状态的线程获得了cpu,开始执行run()方法时,该线程就是运行状态。
当一个线程开始执行之后,他不可能一直是处于运行状态的。线程运行过程中会被中断,以便让其它线程进出执行状态。
线程的死亡
- 当run()方法执行完毕,线程正常结束
- 当线程抛出了一个为捕获的Exception或Error。
- 直接调用线程的stop()方法时。
可以调用线程对象的isAlicve()方法,来查看线程是否死亡。死亡时反回false;
死亡后的线程不能在调用start()方法了;