Java高级--多线程

1.什么是进程

  • 进程就是一个在内存中独立运行的程序,有自己的地址空间。比如正在运行的QQ、微信

  • 多任务:指操作系统能同时运行多个进程(程序),比如Windows系统能同时运行浏览器】写字板、画画、QQ等

2.什么是线程

  • 线程是进程内部单一的一个顺序控制流

  • 一个进程可以拥有多个线程,一个进程至少要有一个线程

3.创建线程

  • 虚拟的CPU:有java.lang.Thread类封装和虚拟

  • CPU执行代码:传递给Thread对象

  • CPU处理的数据:传递给Thread对象

  • java的线程是通过java.lang.Thread类来实现的

  • 每个线程都是通过某个特定的Thread对象所对应的run()方法来完成其操作的,方法run()称为线程体

  • 创建线程的两种方式

    • 继承Thread类

      package com.jxd.edu;
      ​
      /**
       * @author Ming WanBao
       * 1.定义类继承Thread类
       * 2.重写父类的run()方法完成具体的操作
       * 3.创建子类对象,就是创建线程对象
       * 4.调用线程对象的start()方法来启动线程(告诉jvm调用run()方法)
       */
      public class ThreadDemo extends Thread {
          private String name;
      ​
          public ThreadDemo(String name) {
              this.name = name;
          }
      ​
          public ThreadDemo() {
      ​
          }
      ​
          /**
           * 重写run(),在方法体中添加你想要在该线程中执行的代码
           */
          @Override
          public void run() {
              for (int i = 0; i < 500; i++) {
                  System.out.println(name + "运行:" + i);
              }
          }
      }
      package com.jxd.edu;
      ​
      /**
       * @author Ming WanBao
       */
      public class TestThreadDemo {
          public static void main(String[] args) {
              //创建线程对象
              ThreadDemo td1 = new ThreadDemo("A");
              ThreadDemo td2 = new ThreadDemo("B");
              //启动线程
              td1.start();
              td2.start();
              /*
               结果分析:
                  》在任何java程序启动时,一个线程立刻运行,即main方法对应的线程,
                  该线程通常称为程序的主线程,随着start()方法的调用,另外两个线程也启动,
                  这样,整个应用就在多线程下运行了
                  》从程序的运行结果可以发现,多线程程序是乱序执行,谁先抢占到CPU的资源谁先执行
                  》java.lang.Thread类包含了创建和运行线程所需的一切东西
                  》主线程的特点:
                      》它是产生其他子线程的线程
                      》它不一定是最后执行完成的线程,子线程可能在它结束之后还在运行
               */
          }
      ​
      }

    • 实现Runnable接口

      package com.jxd.edu;
      ​
      /**
       * @author Ming WanBao
       * 1.创建类实现RunnableDemo接口
       * 2.重写run()
       * 3.创建Thread类的对象,将Runnable接口的实现类对象作为参数传递给Thread类的构造函数
       * 4.调用Thread类的start()方法
       */
      public class RunnableDemo implements Runnable{
      ​
          private String name;
      ​
          public RunnableDemo() {
          }
      ​
          public RunnableDemo(String name) {
              this.name = name;
          }
      ​
          @Override
          public void run() {
              for (int i = 0; i < 1000; i++) {
                  System.out.println(name + "运行:" + i);
              }
          }
      }
      package com.jxd.edu;
      ​
      /**
       * @author Ming WanBao
       * 实现了Runnable接口的类并不具备任何天生的线程处理能力,
       * 这与那些继承了Thread类的子类是不同的
       * 为了从一个Runnable对象产生线程,必须再单独创建一个线程对象,把Runnable对象作为参数传递给它
       */
      public class TestRunnableDemo {
          public static void main(String[] args) {
              RunnableDemo r1 = new RunnableDemo("A");
              RunnableDemo r2 = new RunnableDemo("B");
              Thread t1 = new Thread(r1);
              Thread t2 = new Thread(r2);
              t1.start();
              t2.start();
      ​
              /*
              两种创建线程方式的比较
                  》继承Thread类
                      》优点:Thread类的子类对象就是线程对象,具有Thread类的方法,且具有线程体
                      》缺点:不适应多继承,因为java是单继承的语言,继承了Thread类就无法继承其他累了
                  》实现Runnable接口
                      》如果一个类已经继承了其他类还必须要以线程方式运行,就需要实现Runnable接口,
                      实现Runnable接口的类可以避免java中单继承的限制
               */
          }
      }

4.join()方法和线程优先级

  • 在线程中插入另一个线程,该线程被阻塞,直到插入的线程执行完毕以后,该线程才继续执行下去

    package com.jxd.edu;
    ​
    /**
     * @author Ming WanBao
     */
    public class TestJoin {
        public static void main(String[] args) {
            RunnableDemo rd = new RunnableDemo("A");
            Thread thread = new Thread(rd);
            //设置子线程的优先级为10
            //thread.setPriority(Thread.MAX_PRIORITY);
            thread.start();
            try {
                //join的作用是让父线程等待子线程运行结束之后再运行
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            for (int i = 0; i < 1000; i++) {
                System.out.println("主线程:" + i);
            }
            /*try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }*/
            /*System.out.println("子线程的优先级为" + thread.getPriority());
            System.out.println("主线程的优先级为" + Thread.currentThread().getPriority());*/
        }
    }

  • 为什么要用join

    • 在很多情况下,主线程产生并启动了子线程,如果子线程中要进行大量的耗时的计算,主线程往往优先于子线程结束,但是如果主线程中需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再执行,这个时候就需要用到join

  • 线程优先级:

    • 在java中,每个线程都有一个优先级,默认情况下,一个线程将继承其父线程的优先级。

    • 线程优先级用数字表示,范围从1-10,一个线程的缺省优先级是5

      • Thread.MIN_PRIORITY ---------1

      • Thread.NORM_PRIORITY ---------5

      • Thread.MAX_PRIORITY ---------10

    • 不是高优先级的线程一定比低优先级的线程先执行完,只是高优先级线程先执行的概率比低优先级线程高

    • 设置优先级:void setPriority(int newPriority);

    • 获取优先级:int getPriority();

5.sleep()

  • sleep()是指在指定的毫秒数内让当前正在执行的线程休眠(暂停运行)

    package com.jxd.edu;
    ​
    /**
     * @author Ming WanBao
     */
    public class TestSleep {
        public static void main(String[] args) {
            ThreadDemo td1 = new ThreadDemo("A");
            td1.start();
            try {
                //让主线程休眠一段时间后重新获取CPU的使用权
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            for (int i = 0; i < 1000; i++) {
                System.out.println("主线程:" + i);
            }
        }
    }

6.yield

  • 主动释放当前线程的执行权

    package com.jxd.edu;
    ​
    /**
     * @author Ming WanBao
     */
    public class YieldDemo extends Thread {
        private String name;
    ​
        public YieldDemo(String name) {
            this.name = name;
        }
    ​
        @Override
        public void run() {
            for (int i = 0; i < 50; i++) {
                System.out.println(name + "执行:" + i);
                if (i == 30) {
                    //当i为30时,该线程会把CPU让出来,让其他线程或自己的线程执行
                    // (也就是谁抢占到CPU谁执行)
                    Thread.yield();
                }
            }
        }
    }
    package com.jxd.edu;
    ​
    /**
     * @author Ming WanBao
     */
    public class TestYieldDemo {
        public static void main(String[] args) {
            Thread t1 = new YieldDemo("A");
            Thread t2 = new YieldDemo("B");
            t1.start();
            t2.start();
        }
    }

7.对象的监视锁

  • 在java中,每个对象都包含了一把锁(也叫监视器),他自动成为对象的一部分,在给定时刻,只有一个线程可以拥有一个对象的锁

8.同步

  • 我们知道,在同一时间只能有一个线程在CPU上运行,线程之间的调度是通过分时和抢占来完成的

  • 为了确保在任何时刻一个共享对象只被一个线程使用,必须使用同步

  • synchronized关键字声明的方法就是同步方法,声明的代码块就是同步块

  • 同步方法

    • synchronized public void setName(){}

  • 同步块

    • synchronized(obj) {}

    • obj是被锁定的对象

  • 作用:

    • 任何时刻,都最多只能有一个线程调用此方法,若有多个线程请求调用此方法,只能排队

9.wait()和notify()

  • wait():当前线程被中断,并进入到一个对象的等待列表中,直到另外的线程调用同一个对象上的notify()或notifyAll()方法

  • notify():用于将对象等待列表中任意一个线程唤醒,使它再次成为可运行的线程

  • notifyAll():用于将对象等待列表中的所有线程唤醒,使它们再次成为可运行的线程

10.线程的生命周期

  1. 新建状态(new):当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态

  2. 就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法,该线程位于可运行线程池中,变得可运行,等待获取CPU的使用权

  3. 运行状态(Running):就绪状态的线程获得了CPU使用权,执行程序代码

  4. 阻塞状态(Blocked):线程因为某种原因放弃了CPU的使用权,暂时停止运行,直到线程进入就绪状态才有机会转到运行状态。sleep() join() yield() wait()

  5. 死亡状态(dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期

  • 16
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值