欢迎光临散文网 会员登陆 & 注册

java线程的创建与结束

2022-08-31 10:50 作者:虚云幻仙  | 我要投稿

/**
* 使用软件时运行软件的程序/可执行文件,操作系统将程序加载到内存中产生进程
* 每个进程都是内存中一块独立运行的程序空间。每个进程由cpu资源、data数据、code代码三部分组成。cpu通过时间片轮转轮流处理每个进程
* 线程为进程中的执行单元(单一的顺序控制流程),进程中至少有一个线程,可拥有多个并行的concurrent线程。
* 同一个进程中的多个线程共享内存地址空间,可以访问相同的变量、对象,从同一堆heap中分配对象并进行通信、数据交换和同步操作
* 相比进程,线程之间信息传递容易,线程的启动、中断、消亡、消耗的资源非常少
* 操作系统为class的main方法创建通往cpu的通道为主线程,子线程通过主线程创建
*/

public class Test1Thread extends Thread {
   //实现多线程方法之一:通过继承Thread类来创建子线程

   @Override
   public void run() {
       //重写run方法,当子线程启动时会执行run方法,将交给子线程执行的内容放在run方法中
       System.out.println("子线程:"+this.getName()+"开始运行");
       //Thread类中的方法.getName()返回当前线程的引用/名字,并非变量名
       for (int i = 0;i<20;i++){
           System.out.println("子线程:"+this.getName()+" 进度:"+i*5+"%");
       }
       System.out.println("子线程:"+this.getName()+"运行结束");
   }

   public Test1Thread(){
       System.out.println("创建子线程:"+this.getName());
   }

   public static void main(String[] args) {
       //通过主线程创建子线程
       System.out.println("主线程开始运行");
       Test1Thread t1 = new Test1Thread();
       t1.start();
       //启动子线程需要通过.start()方法,之后子线程会自行执行run方法,如果直接调用run方法会变成主线程执行对象的方法
       Test1Thread t2 = new Test1Thread();
       //生成多个子线程
       t2.start();
       System.out.println("主线程结束");
       //主线程会在启动两个子线程之后结束,此时子线程任然在执行中,主线程是进程中最先开始的但并不一定是最后结束的
       /*
       结果为:
       主线程开始运行
       创建子线程:Thread-0
       创建子线程:Thread-1
       主线程结束
       子线程:Thread-0开始运行
       子线程:Thread-1开始运行
       子线程:Thread-0 进度:0%
       子线程:Thread-1 进度:0%
       子线程:Thread-1 进度:5%
       子线程:Thread-0 进度:5%
       子线程:Thread-0 进度:10%
       ...
       子线程:Thread-1 进度:95%
       子线程:Thread-0 进度:70%
       子线程:Thread-1运行结束
       子线程:Thread-0 进度:75%
       ...
       子线程:Thread-0 进度:95%
       子线程:Thread-0运行结束

       主线程在创建完子线程后结束,cpu通过时间片轮转轮流处理每个线程,所以线程交替打印内容,操作系统分配给线程的时间片不是固定长度,所以有的线程先完成
        */

   }
}

class Test2Thread implements Runnable{
   //实现多线程方法之二:实现Runnable接口
   @Override
   public void run() {
       //Runnable接口中只有一个run()方法,Thread类同样实现了Runnable接口的run()方法
       System.out.println("子线程:"+Thread.currentThread().getName()+"开始运行");
       //实现Runnable接口的Test2Thread类并不是线程类,通过Thread类静态方法.currentThread()获取当前执行run方法的线程对象,通过线程对象.getName()获取线程对象的String name属性的值,所以不会返回引用变量的名字
       System.out.println("子线程:"+Thread.currentThread().getName()+"运行结束");
   }
   public Test2Thread(){
       System.out.println(this);
       //在构造器中this指当前正在构造的对象
       System.out.println(Thread.currentThread().getName());
       //这里得到的是正在构造Test2对象的线程
   }

   public static void main(String[] args) {
       System.out.println(Thread.currentThread().getName());
       //结果为:main
       //主线程的name是main

       Thread t1 = new Thread(new Test2Thread());
       //Thread(Runnable)构造方法传入Runnable的实现类对象,这个线程在执行run方法时会调用实现类的run方法
       t1.start();
       //通过实现Runnable可以解决继承其他类和继承Thread,继承位不足的问题
       Thread t2 = new Thread(new Test2Thread());
       t2.start();
       System.out.println(Thread.currentThread().getName()+"结束");
       /*
       结果为
       Test2Thread@1b6d3586
       main
       Test2Thread@4554617c
       main
       main结束
       子线程:Thread-1开始运行
       子线程:Thread-0开始运行
       子线程:Thread-0运行结束
       子线程:Thread-1运行结束

       .start()方法只是将线程从新生状态变为就绪状态
       线程的生命周期需要经历5个阶段。
       新生状态new:new Thread()会进入新生状态
       就绪状态runnable:所有排队等待获得cpu的线程都处于就绪状态/可运行状态。1.对新生状态的线程执行.start()会变为就绪状态2.从阻塞状态结束后回到就绪状态3.运行状态执行完分配的时间片后JVM将cpu资源从本线程切换到其他线程会回到就绪状态4.运行状态中run方法执行到yield()方法会立即回到就绪状态
       运行状态running:获得cpu资源执行run方法,每次执行都从上一次执行完的代码的下一代码开始往下进行
       阻塞状态blocked:在运行状态时执行run方法中因为某些原因无法向下执行代码,线程进入阻塞状态JVM将cpu资源切换到其他线程。1.Thread.sleep(long ms)使当前线程休眠,进入阻塞状态,指定时间到后进入就绪状态2.执行.wait()方法使进入阻塞状态,需要等待notify()方法唤醒notify通知3.执行io操作等会阻塞的操作,当阻塞的原因消失(.read等待数据返回.write等待数据写入)后进入就绪状态4.join()线程联合,等待另一个线程执行结束才能继续执行5.同步锁synchronized
       死亡状态terminated:线程完成了run方法或者被stop()destroy()强制终止后进入死亡状态,无法回到其他状态
        */

   }
}

class Test3Thread implements Runnable{
   //测试线程的结束
   boolean notFinish = true;
   //设置一个标记,当需要结束线程时将标记变为false
   @Override
   public void run() {
       System.out.println(Thread.currentThread().getName()+"开始");
       for (int i=0;notFinish;i++){
           System.out.println("执行次数:"+i);
           try {
               Thread.sleep(1000);
           } catch (InterruptedException e) {
               throw new RuntimeException(e);
           }
       }
       System.out.println(Thread.currentThread().getName()+"结束");
   }
   public void over(){
       notFinish=false;
       //结束线程的方法
   }

   public static void main(String[] args) {
       System.out.println("主线程开始");
       Test3Thread t3 = new Test3Thread();
       new Thread(t3).start();
       //子线程进入就绪状态,如果这时调用over()方法子线程在进入运行状态后不会执行循环。如果要通过主线程关闭子线程并且让子线程执行一段时间后再结束,主线程就不能过早结束,可以让主线程阻塞来延长生命周期
       try {
           System.in.read();
           //System.in.read()会等待用户输入,单次read()只会返回第一个字节,但目的不是读取内容而是利用io操作造成阻塞,当用户随意输入内容回车之后主线程向下执行
       } catch (IOException e) {
           throw new RuntimeException(e);
       } finally {
           try {
               System.in.close();
           } catch (IOException e) {
               throw new RuntimeException(e);
           }
       }
       t3.over();
       System.out.println("主线程结束");
       /*
       主线程开始
       Thread-0开始
       执行次数:0
       执行次数:1
       执行次数:2

       主线程结束
       Thread-0结束

       主线程调用over()后,子线程停止循环,将循环外/下面的语句执行完毕后安全结束
        */

   }
}

java线程的创建与结束的评论 (共 条)

分享到微博请遵守国家法律