Java学习笔记之线程(一):线程的创建和生命周期

来源:互联网 发布:昆明理工大学教育网络 编辑:程序博客网 时间:2024/05/18 05:18


package com.demo;/** * 进程:正在运行的程序叫做进程,进程负责了这个程序的内存空间分配,代表了内存中的执行区域; *  * 问题:Windows号称是多任务的操作系统,那么Windows是同时运行多个应用程序吗? * 从宏观角度:从感知和能看得到的现象来说,确实是同时运行多个应用程序的; * 从微观角度:由于CPU分时机制的作用,使每个进程都能循环获得自己的CPU时间片,但因为轮换速度非常快, * 所以看起来好像所有的程序都在同时运行一样; *  * 线程:线程在一个进程中负责了代码的执行,就是进程中一个执行路径; * 多线程:就是在一个进程中多个执行路径同时执行; *  * 运行任何一个Java程序,jvm在运行的时候都会创建一个main线程,来执行main方法中的所有代码; *  * 问题:一个java程序至少有几个线程? * 至少有两个线程,一个是主线程负责main方法代码的执行,一个是垃圾回收器线程,负责垃圾的回收; *  * 多线程的好处: * 1、解决了一个进程能同时执行多个任务的问题; * 2、提高了资源的利用率,而不是提高效率; * 多线程的弊端: * 1、对线程进行管理要求额外的CPU开销,增加了CPU的负担; * 2、降低了一个进程中线程的执行效率; * 3、引发了线程安全问题;当多个线程需要对公有资源进行操作时,后一个线程往往会修改掉前一个线程保存的数据; * 4、出现了死锁现象;即较长时间的等待或资源竞争; *  * 线程的创建有两种方法: * 方法一: * 1、自定义一个类继承Thread类; * 2、重写Thread类的 run() 方法; * 问题:为什么要重写 run() 方法? * 每个线程都有自己的任务代码,jvm创建的主线程的任务代码就是 main() 方法中的所有代码, * 而自定义线程的任务代码就是run() 方法中的所有代码。 *3、创建Thread的子类对象,并且调用 start() 方法开启线程; *注意:一个自定义线程一旦开启,就会执行 run() 方法中的任务代码;run() 方法不能直接调用, *因为直接调用就相当于调用了一个普通方法,并没有开启线程; *  * 线程的生命周期:如下图所示: * CPU的等待资格:具有CPU等待资格的线程,表示CPU在切换的时候有可能执行的线程; * CPU的执行权:具有CPU执行权的线程,表示CPU正在执行的线程; *  * 1、Demo1 d = new Demo1():当线程对象被 new 出来的时候,线程处于“创建状态”,该状态下的线程不具备任何资格; * 2、d.start():调用线程的 start() 方法,线程进入“可运行状态”,该状态的线程具备CPU等待资格,不具备CPU执行权; * 3、当线程得到CPU的执行权,进入“运行状态”,此时线程具备CPU的执行权,也具备CPU的等待资格; * 4、如果线程在执行过程中被抢走了CPU的执行权,线程将重新进入“可运行状态”; * 5、当线程执行完任务代码后,就进入了“死亡状态”。 * 6、除了 “创建状态->可运行状态->运行状态->死亡状态”,这四种正常状态之外,线程还存在一种“临时阻塞状态”; * 当“运行状态”下的线程执行了 sleep() 方法或者 wait() 方法,线程就会进入“临时阻塞状态”; * 如果线程是调用了sleep()方法进入的“临时阻塞状态”,那么一旦超过指定的睡眠时间,就会重新进入“可运行状态”; * 如果线程是调用了wait()方法进入的“临时阻塞状态”,那么需要其他线程唤醒该线程,才可以重新进入“可运行状态”; *  */public class Demo1 extends Thread {@Overridepublic void run() {// 执行自定义线程的任务代码for (int i = 0; i < 100; i++){System.out.println("自定义线程: " + i);}}public static void main(String[] args) {// 创建自定义线程对象Demo1 d = new Demo1();//d.run();// 没有开启线程,只是在主线程中调用了一个普通方法d.start();// 启动线程for (int i = 0; i < 100; i++){System.out.println("main线程: " + i);}}}




package com.demo;/* * 线程的创建方式二: * 1、自定义一个类实现Runnable接口; * 2、实现Runnable接口的run方法,把自定义线程的任务代码写在run方法上; * 3、创建Runnable实现类对象; * 4、创建Thread类的对象,并且把Runnable实现类的对象作为实参传递; * 5、调用Thread对象的start()方法开启线程; *  * 问题1:请问Runnable实现类的对象是线程对象吗? * 不是线程对象,只不过是实现了Runnable接口的普通对象而已; * 只有Thread或者Thread的子类对象才是线程对象; *  * 问题2:为什么要把Runnable实现类的对象作为实参传递给Thread对象?作用是什么? * 从Thread类的源码可以看出,创建Thread对象的时候,可以把Runnable实现类的对象传递过去,用target保存; * public Thread(Runnable target, String name) { * init(null, target, name, 0); *}  *当调用Thread对象的start()方法开启线程的时候,实际上就是执行了Thread对象的run()方法,源码如下: *@Override *public void run() { *if (target != null) { *target.run(); *} *} *可以看出,执行run()方法的时候,实际上就是执行Runnable实现类的run()方法; *作用也就是把Runnable实现类的对象的run()方法,作为线程的任务代码去执行; *  */public class Demo6 implements Runnable {// 2、实现Runnable接口的run方法,把自定义线程的任务代码写在run方法上;@Overridepublic void run() {System.out.println("this:" + this);// 此处this表示当前类对象,不是当前线程对象;System.out.println("Thread.currentThread():" + Thread.currentThread());for (int i = 0; i < 50; i++){System.out.println(Thread.currentThread().getName() + ":" + i);}}public static void main(String[] args) {// 3、创建Runnable实现类对象;Demo6 d = new Demo6();// 4、创建Thread类的对象,并且把Runnable实现类的对象作为实参传递;Thread t = new Thread(d, "自定义线程");// 5、调用Thread对象的start()方法开启线程;t.start();for (int i = 0; i < 50; i++){System.out.println("main线程:" + i);}}}


原创粉丝点击