zoukankan      html  css  js  c++  java
  • day11_多线程(线程生命周期,Runnable)


    线程概述:

    /*
    1.进程:是一个正在执行中的程序
      
      每一个进程的执行都有一个执行顺序.该顺序是一个执行路径
              或者叫一个控制单元.
            进程用于封装控制单元
    
    2.线程:就是进程中的一个独立的控制单元
            线程在控制着进程的执行.
    
    一个进程中至少有一个线程
    
    JVM启动的时候会有一个进程java.exe.
    
    该进程中至少有一个线程负责java程序的执行
    而且这个线程运行的代码存在于main方法中
    该线程称之为主线程
    
    扩展:其实更细说明JVM,JVM启动不止一个线程,还有负责垃圾回收机制的线程.
         这是因为,当某个对象不被引用时,会变成垃圾
    
    多线程存在的意义:
       如果没有多线程,只有主线程.不停的执行过程中,当堆内存产生n多垃圾
       无法在堆内存分配空间,这时候主程序必须停掉,回头把垃圾处理
    
       反之,一边执行,一边扔垃圾(多线程)-->提高了效率
    */
    
    
    
    class ThreadDemo 
    {
        public static void main(String[] args) 
        {
             
            System.out.println("Hello World!");
        }
    }

    创建线程:

    /*
    1.如何在自定义代码中,自定义一个线程??
      通过对api的查找,java已经提供了对线程这类事物的描述->Thread类
    创建线程的一种方式:继承Thread类.
    步骤:
     1.定义类继承Thread
     2.复写Thread类中的run();
        目的:将自定义代码存储在run方法中,让线程运行
     3.调用线程的start方法
        作用:①启动线程②JVM调用该线程的 run 方法。
    
    发现每次运行结果均不相同:
     因为多个线程都在获取cpu的执行权.cpu执行到谁,谁就运行
      明确一点,在某一个时刻,只能有一个线程在运行.(多核除外)
    cpu在做着快速的切换(实际上cpu在切换进程中的线程),宏观看上去是同时运行的效果
    
    我们可以形象把多线程的运行行为在互相争夺cpu的执行权
    
    
    
    这就是多线程的一个特性:随机型.谁抢到谁执行,至于执行多长,cpu说的算.
    
    (画一个示意图)
    */
    class Demo extends Thread
    {
        public void run()
        {
          for(int i=0;i<10;++i)
          System.out.println("demo run----"+i);
        }
    }
    
    
    class ThreadDemo2 
    {
        public static void main(String[] args) 
        {
             
        Demo d=new Demo();//创建一个线程,还没有执行
         d.start();
        //d.run();//仅仅是对象调用run方法.线程创建了,并没有运行.(只有主线程)
        for(int i=0;i<10;++i)
          System.out.println("Hello world----"+i);
        }
    }
    /*
    以上主线程和new Demo()线程
    即使主线程先执行完,还有new Demo()
    java.exe(进程)还在,执行new Demo()线程
    */
    
    
    /*
    为什么要覆盖run方法呢??
    
        Thread类用于描述线程
        该类就定义了一个功能,用于存储线程要运行的代码.该存储功能就是run方法
    
        也就是说Thread类中的run方法,用于存储线程要运行的代码
        主线程要运行的代码存储在main方法中
    
    */

    其中一种打印结果:

    ThreadDemo2

    关于以上两个线程的示意图:
    线程

    小练习:

    /*
    练习:
    创建两个线程,和主线程交替执行.
    
    线程都有自己默认的名称
        Thread-编号 该编号从0开始
    
    currentThread:返回对当前正在执行的线程对象的引用
     static Thread currentThread() 
    getName():获取线程名称
     String getName()
    
    设置线程名称:setName()或者利用构造函数
    void setName(String name)
    均可查API文档
    */
    class Test extends Thread
    {
        //自定义线程名称
        Test(String name)
        {
          super(name);
        }
        public void run()
        {
            for(int x=0;x<60;x++)
             System.out.println(this.getName()+" test run..."+x);
            //在这里同样可以使用currentThread.getName(),通用方法
            
        }
    }
    class ThreadTest
    {
     public static void main(String[] args)
     {
       Test t1=new Test("one");
       Test t2=new Test("two");
       t1.start();
       t2.start();
      for(int x=0;x<60;++x)
       System.out.println("main"+x);
     
     } 
    
    
    }

    ThreadTest

    线程的生命周期:

    线程生命周期3

    /*
    以下均摘自李刚老师的疯狂java(略有改动):
    
    新建和就绪状态:
        当程序使用new关键字创建了一个线程之后,该线程就处于新建状态,此时它和其他
        java对象一样,仅仅由JVM为其分配了内存,并初始化了其成员变量的值.此时的线程对象
        没有表现出任何线程的动态特征,程序也不会执行线程执行体中的代码.
    
        当对象调用了start()方法之后,该线程
        处于就绪状态(万事具备,只欠CPU),JVM会为其创建方法调用栈和程序计数器,处于这个状态的
        线程并没有开始运行,它只是表示该线程可以运行了.至于该线程何时开始运行,取决于JVM里线程调度
        器的调度.
    
    运行和阻塞状态:
        如果处于就绪状态的线程获得了CPU,开始执行run方法的线程执行体,则该线程处于运行状态.
        如果计算机只有一个CPU,在任何时刻只有一条线程处于运行状态
        但当线程数大于处理器数时,依然会有多条线程在同一个CPU上轮换的现象
    
        当一个线程开始运行后,它不可能一直处于运行状态(除非它的线程执行体足够短,瞬间就执行结束了)
        ,线程在运行过程中需要被中断,目的是使其他线程获得执行的机会,线程调度的细节取决于底层平台所采用
        的策略(windows下的JVM会调用windows底层内容)
    */

    由售票例子引出线程第二种创建方式:

    /*
    需求:简单的卖票程序.
    多个窗口买票.
    
    创建线程的第二种方式:实现Runable接口
    
    步骤:
    1.定义类实现Runnable接口
    2.覆盖Runnable接口中的run方法
       将线程要运行的代码存放在该run方法中
    
    3.通过Thread类建立线程对象.
    4.将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
       
       为什么要将Runnable接口的子类对象传递给Thread的构造函数??
       
       因为,自定的run方法 所属的对象 是Runnable接口的子类 对象
       所以要让线程去执行 指定对象 的run方法.(就必须明确该run方法所属的对象.)
    
    5.调用Thread类的start方法开启线程并调用Runnable接口子类对象 的run方法
    */
    
    /*
    class Ticket extends Thread
    {
        //private static int ticket=100;//让四个对象共享100张票
        private int ticket=100;    //一般不定义static,生命周期过长                            
        public void run()
        {
           while(true)
             if(ticket>0)
               System.out.println(currentThread().getName()+"Sale :"+ticket--);
           
        }
    }
    */
    class Ticket implements Runnable
    {
          private int ticket=100;//ticket此时被共享        
            public void run()
            { 
                while(true)         
                if(ticket>0)
                 System.out.println(Thread.currentThread().getName()+" Sale :"+ticket--);
                    
            }
    
    
    }
    
    class TicketDemo
    {
      public static void main(String[] args)
      {
            //new Ticket().start();
            //new Ticket().start();
            //new Ticket().start();
            //new Ticket().start();
             //以上相当于每台卖了100张,不符合实际
             /*
             Ticket t=new Ticket();
             t.start();
             t.start();
             t.start();
             t.start();
             */
         //以上会有运行提示:无效线程状态异常
         //这是因为已经启动线程,并且从就绪状态到运行状态
         //又启动了线程
       
       
       Ticket t=new Ticket();
       //注意这个对象不是线程对象,和Thread没关系
     
    /*
      new Thread().start();//执行的为Thread类中的run方法->方法体中无内容->什么也没执行
      */

    new Thread(t).start(); new Thread(t).start(); new Thread(t).start(); new Thread(t).start(); //四个线程对象,同一个Runnable子类对象,自始至终改变的是该runnable子类对象中的ticket } } /* 实现方式和继承方式有什么区别??? 实现方式好处:避免了单继承的局限性 在定义线程时,建议使用实现方式. 两种方式区别: 继承Thread:线程代码存放Thread子类run方法中. 实现Runnable:线程代码存放在接口的子类的run方法. 例如: person<-student student不能再继承Thread 如果想让student中部分代码在线程中执行,可以实现Runnable,并复写run方法 */
    /*
    运行结果的打印顺序
    是由于多核造成的,先出来的不一定被先打印
    */

    Ticket1

  • 相关阅读:
    .NET Framework 概述
    .Net笔试(二)
    EF CodeFirst 创建数据库
    C#中的继承
    SqlHelper 基类
    在C#中实现OOP概念
    索引器、委托和事件
    .Net笔试(一)
    HTML标签速记整理W3C
    Java函数调用总结
  • 原文地址:https://www.cnblogs.com/yiqiu2324/p/2963290.html
Copyright © 2011-2022 走看看