多线程,线程终止,Thread,Runnable接口,多个子线程

  1. 程序:为完成特定任务,用某种语言编写的一组指令的集合。简单说就是代码
  2. 进程:指运行的程序,操作系统就会为进程分配内存空间
  3. 进程是程序的一次执行过程,或是正在运行的一个程序。是动态过程:有它自身的产生,存在,和消亡的过程
  4. 线程由进程创建的,是线程的一个实体
  5. 一个进程可以拥有多个线程
  6. 单线程:同一个时刻,只允许执行一个线程
  7. 多线程:同一个时刻,可以执行多个线程,qq可以打开多个聊天窗口,迅雷同下载多个文件
  8. 并发:同一个时刻,多个任务交替执行,造成一种"貌似同时"的错觉,简单的说,单核cpu实现的多任务就是并发
  9. 并行:同一个时刻,多个任务同时执行。多核cpu可以实现并行
  10. 创建线程的两种方式
    1. Thread
      package com.jshedu.cpu_;
      
      /**
       * @author Mr.jia
       * @version 1.0
       */
      
      public class Thread01 {
          public static void main(String[] args) {
              //创建一个Cat对象,可以当做线程使用了
              Cat cat = new Cat();
      
              //为什么用start方法,调用run方法,不直接调用run方法
              //如果直接调用run(),那么就是main线程里的一个普通方法,并没有
              //真正启动一个线程。也不会主线程子线程交替执行了。主线程会阻塞在这里等run
              //方法执行完之后在执行主线程
      
              /*源码
                  (1)
                  public synchronized void start() {
                      start0();
                  }
                  (2)
                  //start0() 是本地方法,是JVM调用, 底层是c/c++实现
                  //真正实现多线程的效果, 是start0(), 而不是 run
                  private native void start0();
      
              
               */
              cat.start();//启动线程,main的子线程
      
              //当main线程启动一个子线程,主线程不会阻塞,会继续执行
              //主线程和子线程是交替执行
      
              for (int i = 0; i < 60; i++) {
                  System.out.println("主线程"+i);//主线程
                  try {
                      Thread.sleep(1000);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
      
          }
      }
      /*
      1.当一个类继承Thread类,该类就可以当做线程使用
      2.我们会重写run方法,写上自己的业务代码
      3.run Thread类 实现了 Runnable 接口的run方法
          @Override
          public void run() {
              if (target != null) {
                  target.run();
              }
          }
      
      
       */
      class Cat extends Thread{
          int time=0;
          @Override
          public void run() {//重写run方法,写上自己的业务逻辑
              while (true){
                  //该进程每隔1秒在控制台输出
                  System.out.println("喵喵喵"+(++time));
                  //该线程休眠1秒ctrl+alt+t
                  try {
                      Thread.sleep(1000);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
                  if(time == 80){
                      break;//当time达到指定次数,线程就退出了
                  }
              }
      
      
          }
      }
      

      用start(),不用run()

    2. java是单继承,某些情况下一个类可能已经继承了某个父类,这时在用继承Thread类方法来创建线程显然不可能了。

    3. 通过实现Runnable接口来创建线程

    4. package com.jshedu.cpu_;
      
      /**
       * @author 韩顺平
       * @version 1.0
       * 通过实现接口Runnable 来开发线程
       */
      public class Thread02 {
          public static void main(String[] args) {
              Dog dog = new Dog();
              //dog.start(); 这里不能调用start,因为是实现Runnable接口里面没有start()
              //创建了Thread对象,把 dog对象(实现Runnable),放入Thread
              Thread thread = new Thread(dog);//设计模式:代理模式
              thread.start();
      
      //        Tiger tiger = new Tiger();//实现了 Runnable
      //        ThreadProxy threadProxy = new ThreadProxy(tiger);
      //        threadProxy.start();
          }
      }
      
      class Animal {
      }
      
      class Tiger extends Animal implements Runnable {
      
          @Override
          public void run() {
              System.out.println("老虎嗷嗷叫....");
          }
      }
      
      //线程代理类 , 模拟了一个极简的Thread类
      class ThreadProxy implements Runnable {//你可以把Proxy类当做 ThreadProxy
      
          private Runnable target = null;//属性,类型是 Runnable
      
          @Override
          public void run() {
              if (target != null) {
                  target.run();//动态绑定(运行类型Tiger)
              }
          }
      
          public ThreadProxy(Runnable target) {
              this.target = target;
          }//先走这
      
          public void start() {
              start0();//这个方法时真正实现多线程方法
          }//在走这
      
          public void start0() {
              run();
          }
      }
      
      
      class Dog implements Runnable { //通过实现Runnable接口,开发线程
      
          int count = 0;
      
          @Override
          public void run() { //普通方法
              while (true) {
                  System.out.println("小狗汪汪叫..hi" + (++count) + Thread.currentThread().getName());
      
                  //休眠1秒
                  try {
                      Thread.sleep(1000);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
      
                  if (count == 10) {
                      break;
                  }
              }
          }
      }
      

      就是有的类继承了其他的类,这时在用继承Thread类方法来创建线程显然不可能了。现在实现Runnable接口来创建线程,Runnable里有run方法重写,Runnable里没有start方法,通过构造器传入参数【Runnable target,的实现类也行】,调用该类的方法

    5. 多个子线程案例

      package com.hspedu.threaduse;
      
      /**
       * @author 韩顺平
       * @version 1.0
       * main线程启动两个子线程
       */
      public class Thread03 {
          public static void main(String[] args) {
      
              T1 t1 = new T1();
              T2 t2 = new T2();
              Thread thread1 = new Thread(t1);
              Thread thread2 = new Thread(t2);
              thread1.start();//启动第1个线程
              thread2.start();//启动第2个线程
              //...
      
          }
      }
      
      class T1 implements Runnable {
      
          int count = 0;
      
          @Override
          public void run() {
              while (true) {
                  //每隔1秒输出 “hello,world”,输出10次
                  System.out.println("hello,world " + (++count));
                  try {
                      Thread.sleep(1000);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
                  if(count == 60) {
                      break;
                  }
              }
          }
      }
      
      class T2 implements Runnable {
      
          int count = 0;
      
          @Override
          public void run() {
              //每隔1秒输出 “hi”,输出5次
              while (true) {
                  System.out.println("hi " + (++count));
                  try {
                      Thread.sleep(1000);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
                  if(count == 50) {
                      break;
                  }
              }
          }
      }
      

      这里面main线程把Thread1和Thread2启动后就停掉了,没有过多的功能

  11. 继承Thread vs 实现Runnable的区别

    1. 从java的设计来看,通过继承Thread或者实现Runnable接口来创建线程本质没有区别,都是实现了Runnable接口

    2. 实现Runnable接口方式更加适合多个线程共享一个资源的情况,并且避免了单继承的限制,建议使用。

  12. 售票系统案例

  13. 线程终止:启动一个线程t,要求在main线程中去停止线程t,请编程实现

    package com.hspedu.exit_;
    
    /**
     * @author 韩顺平
     * @version 1.0
     */
    public class ThreadExit_ {
        public static void main(String[] args) throws InterruptedException {
            T t1 = new T();
            t1.start();
    
            //如果希望main线程去控制t1 线程的终止, 必须可以修改 loop
            //让t1 退出run方法,从而终止 t1线程 -> 通知方式
    
            //让主线程休眠 10 秒,再通知 t1线程退出
            System.out.println("main线程休眠10s...");
            Thread.sleep(10 * 1000);
            t1.setLoop(false);
        }
    }
    
    class T extends Thread {
        private int count = 0;
        //设置一个控制变量
        private boolean loop = true;
        @Override
        public void run() {
            while (loop) {
    
                try {
                    Thread.sleep(50);// 让当前线程休眠50ms
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("T 运行中...." + (++count));
            }
    
        }
    
        public void setLoop(boolean loop) {
            this.loop = loop;
        }
    }
    
    

你可能感兴趣的:(jvm,java,开发语言)