zoukankan      html  css  js  c++  java
  • 00100_多线程

    1、多线程介绍

      (1)进程:进程指正在运行的程序。确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能;

      打开任务管理器的方法参考:01011_怎么打开任务管理器?win7打开任务管理器方法

      

      (2)线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序;

      (3)一个程序运行后至少有一个进程,一个进程中可以包含多个线程。

      (4)什么是多线程呢?

        ①即就是一个程序中有多个线程在同时执行;

        ②单线程程序:即,若有多个任务只能依次执行。当上一个任务执行结束后,下一个任务开始执行,一条队。

        ③多线程程序:即,若有多个任务可以同时执行,N条队。

    2、程序运行原理

      (1)分时调度

        ①所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间。

      (2)抢占式调度

        ②优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。

    3、抢占式调度

      (1)大部分操作系统都支持多进程并发运行,现在的操作系统几乎都支持同时运行多个程序;

      (2)实际上,CPU(中央处理器)使用抢占式调度模式在多个线程间进行着高速的切换。对于CPU的一个核而言,某个时刻,只能执行一个线程,而 CPU的在多个线程间切换速度相对我们的感觉要快,看上去就是在同一时刻运行;

      (3)其实,多线程程序并不能提高程序的运行速度,但能够提高程序运行效率,让CPU的使用率更高。

    4、主线程

      (1)如果在执行过程遇到循环时间比较长的代码,那么在循环之后的其他代码是不会被马上执行的;

     1 class Demo {
     2     String name;
     3 
     4     Demo(String name) {
     5         this.name = name;
     6     }
     7 
     8     void show() {
     9         for (int i = 1; i <= 100000000; i++) {
    10             System.out.println("name=" + name + ",i=" + i);
    11         }
    12     }
    13 }
    14 
    15 class ThreadDemo {
    16     public static void main(String[] args) {
    17         Demo d = new Demo("张三");
    18         Demo d2 = new Demo("李四");
    19         d.show();
    20         d2.show();
    21         System.out.println("Hello World!");
    22     }
    23 }

      

      (2)若在上述代码中show方法中的循环执行次数很多,这时在d.show();下面的代码是不会马上执行的,并且在dos窗口会看到不停的输出name=张三,i=值,这样的语句。为什么会这样呢?

        ①原因是:jvm启动后,必然有一个执行路径(线程)从main方法开始的,一直执行到main方法结束,这个线程在java中称之为主线程;

        ②当程序的主线程执行时,如果遇到了循环而导致程序在指定位置停留时间过长,则无法马上执行下面的程序,需要等待循环结束后能够执行。

      (3)那么,能否实现一个主线程负责执行其中一个循环,再由另一个线程负责其他代码的执行,最终实现多部分代码同时执行的效果?

        ①能够实现同时执行;

        ②通过Java中的多线程技术来解决该问题。

    5、Thread类

      (1)Thread是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程;

      (2)一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。创建对象,开启线程。run方法相当于其他线程的main方法;

      (3)另一种方法是声明一个实现 Runnable 接口的类。该类然后实现 run 方法。然后创建Runnable的子类对象,传入到某个线程的构造方法中,开启线程。

    6、创建线程方式一继承Thread类

      (1)创建线程的步骤:

        ① 定义一个类继承Thread;

        ②重写run方法;

        ③创建子类对象,就是创建线程对象;

        ④调用start方法,开启线程并让线程执行,同时还会告诉jvm去调用run方法。

      (2)代码演示:

        ①自定义线程类

     1 public class MyThread extends Thread {
     2     //定义指定线程名称的构造方法
     3     public MyThread(String name) {
     4         //调用父类的String参数的构造方法,指定线程的名称
     5         super(name);
     6     }
     7     /**
     8      * 重写run方法,完成该线程执行的逻辑
     9      */
    10     @Override
    11     public void run() {
    12         for (int i = 0; i < 10; i++) {
    13             System.out.println(getName()+":正在执行!"+i);
    14         }
    15     }
    16 }

        ②测试类

     1 public class Demo01 {
     2     public static void main(String[] args) {
     3         // 创建自定义线程对象
     4         MyThread mt = new MyThread("新的线程!");
     5         // 开启新线程
     6         mt.start();
     7         // 在主方法中执行for循环
     8         for (int i = 0; i < 10; i++) {
     9             System.out.println("main线程!" + i);
    10         }
    11     }
    12 }

      (3)线程对象调用 run方法和调用start方法区别?

        ①线程对象调用run方法不开启线程,仅是对象调用方法;

        ②线程对象调用start开启线程,并让jvm调用run方法在开启的线程中执行。

      (4)继承Thread类原理

        ①为什么要继承Thread类,并调用其的start方法才能开启线程呢?

        继承Thread类:因为Thread类用来描述线程,具备线程应该有功能。

        ②为什么不直接创建Thread类的对象呢?如下代码:

    Thread t1 = new Thread();
    t1.start();

        这样做没有错,但是该start调用的是Thread类中的run方法,而这个run方法没有做什么事情,更重要的是这个run方法中并没有定义我们需要让线程执行的代码。

        ③创建线程的目的是什么?

        是为了建立程序单独的执行路径,让多部分代码实现同时执行。也就是说线程创建并执行需要给定线程要执行的任务;

        ④对于之前的主线程,它的任务定义在main函数中。自定义线程需要执行的任务都定义在run方法中;

        ⑤Thread类run方法中的任务并不是我们所需要的,只有重写这个run方法。既然Thread类已经定义了线程任务的编写位置(run方法),那么只要在编写位置(run方法)中定义任务代码即可。

      (5)获取线程名称

        ①hread.currentThread()获取当前线程对象;

        ②Thread.currentThread().getName();获取当前线程对象的名称。

        ③获取线程名字Thread类方法getName

     1 /*
     2      *  获取线程名字,父类Thread方法
     3      *    String getName()
     4      */
     5     public class NameThread extends Thread{
     6       
     7       public NameThread(){
     8         super("小强");
     9       }
    10       
    11       public void run(){
    12         System.out.println(getName());
    13       }
    14     }
    15     
    16     /*
    17      *  每个线程,都有自己的名字
    18      *  运行方法main线程,名字就是"main"
    19      *  其他新键的线程也有名字,默认 "Thread-0","Thread-1"
    20      *  
    21      *  JVM开启主线程,运行方法main,主线程也是线程,是线程必然就是
    22      *  Thread类对象
    23      */
    24     public class ThreadDemo {
    25       public static void main(String[] args) {
    26         NameThread nt = new NameThread();
    27         nt.start();
    28         
    29          
    30 
    31       }
    32     }

        ④获取线程名字Thread类方法currentThread

     1 /*
     2     *  获取线程名字,父类Thread方法
     3     *    String getName()
     4     */
     5    public class NameThread extends Thread{
     6 
     7      public void run(){
     8        System.out.println(getName());
     9      }
    10    }
    11    
    12    /*
    13     *  每个线程,都有自己的名字
    14     *  运行方法main线程,名字就是"main"
    15     *  其他新键的线程也有名字,默认 "Thread-0","Thread-1"
    16     *  
    17     *  JVM开启主线程,运行方法main,主线程也是线程,是线程必然就是
    18     *  Thread类对象
    19     *  Thread类中,静态方法
    20     *   static Thread currentThread()返回正在执行的线程对象
    21     */
    22    public class ThreadDemo {
    23      public static void main(String[] args) {
    24        NameThread nt = new NameThread();
    25        nt.start();
    26        
    27        /*Thread t =Thread.currentThread();
    28        System.out.println(t.getName());*/
    29        System.out.println(Thread.currentThread().getName());
    30 
    31 
    32      }
    33    }

    7、创建线程方式—实现Runnable接口

      (1)创建线程的另一种方法是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后创建Runnable的子类对象,传入到某个线程的构造方法中,开启线程;

      (2)查看Runnable接口说明文档:Runnable接口用来指定每个线程要执行的任务。包含了一个 run 的无参数抽象方法,需要由接口实现类重写该方法。

      (3)创建线程的步骤:

        ①定义类实现Runnable接口;

        ②覆盖接口中的run方法;

        ③创建Thread类的对象;

        ④将Runnable接口的子类对象作为参数传递给Thread类的构造函数;

        ⑤调用Thread类的start方法开启线程。

      (4)代码演示:

        ①自定义线程执行任务类

     1 public class MyRunnable implements Runnable {
     2 
     3     // 定义线程要执行的run方法逻辑
     4     @Override
     5     public void run() {
     6 
     7         for (int i = 0; i < 10; i++) {
     8             System.out.println("我的线程:正在执行!" + i);
     9         }
    10     }
    11 }

        ②测试类

     1 public class Demo02 {
     2     public static void main(String[] args) {
     3         // 创建线程执行目标类对象
     4         Runnable runn = new MyRunnable();
     5         // 将Runnable接口的子类对象作为参数传递给Thread类的构造函数
     6         Thread thread = new Thread(runn);
     7         Thread thread2 = new Thread(runn);
     8         // 开启线程
     9         thread.start();
    10         thread2.start();
    11         for (int i = 0; i < 10; i++) {
    12             System.out.println("main线程:正在执行!" + i);
    13         }
    14     }
    15 }

      (5)实现Runnable的原理

        ①为什么需要定一个类去实现Runnable接口呢?继承Thread类和实现Runnable接口有啥区别呢?

        实现Runnable接口,避免了继承Thread类的单继承局限性。覆盖Runnable接口中的run方法,将线程任务代码定义到run方法中;

        创建Thread类的对象,只有创建Thread类的对象才可以创建线程。线程任务已被封装到Runnable接口的run方法中,而这个run方法所属于Runnable接口的子类对象,所以将这个子类对象作为参数传递给Thread的构造函数,这样,线程对象创建时就可以明确要运行的线程的任务。

      (6)实现Runnable的好处

        ①第二种方式实现Runnable接口避免了单继承的局限性,所以较为常用;

        ②实现Runnable接口的方式,更加的符合面向对象,线程分为两部分,一部分线程对象,一部分线程任务;

        ③继承Thread类,线程对象和线程任务耦合在一起。一旦创建Thread类的子类对象,既是线程对象,有又有线程任务;

        ④实现runnable接口,将线程任务单独分离出来封装成对象,类型就是Runnable接口类型。Runnable接口对线程对象和线程任务进行解耦。

    8、线程的匿名内部类使用

      (1)使用线程的内匿名内部类方式,可以方便的实现每个线程执行不同的线程任务操作;

      (2)方式1:创建线程对象时,直接重写Thread类中的run方法;

    1 new Thread() {
    2             public void run() {
    3                 for (int x = 0; x < 40; x++) {
    4                     System.out.println(Thread.currentThread().getName()
    5                             + "...X...." + x);
    6                 }
    7             }
    8         }.start();

      (3)方式2:使用匿名内部类的方式实现Runnable接口,重新Runnable接口中的run方法;

    1 Runnable r = new Runnable() {
    2             public void run() {
    3                 for (int x = 0; x < 40; x++) {
    4                     System.out.println(Thread.currentThread().getName()
    5                             + "...Y...." + x);
    6                 }
    7             }
    8         };
    9         new Thread(r).start();

    public class MyThread extends Thread {

        //定义指定线程名称的构造方法

        public MyThread(String name) {

            //调用父类的String参数的构造方法,指定线程的名称

            super(name);

        }

        /**

         * 重写run方法,完成该线程执行的逻辑

         */

        @Override

        public void run() {

            for (int i = 0; i < 10; i++) {

                System.out.println(getName()+":正在执行!"+i);

            }

        }

    }

  • 相关阅读:
    Atitti 图像处理 图像混合 图像叠加 blend 原理与实现
    Atitit Gaussian Blur 高斯模糊 的原理and实现and 用途
    Atitit 图像处理 灰度图片 灰度化的原理与实现
    Atitit (Sketch Filter)素描滤镜的实现  图像处理  attilax总结
    Atitit 实现java的linq 以及与stream api的比较
    Atitit attilax在自然语言处理领域的成果
    Atitit 图像处理 常用8大滤镜效果 Jhlabs 图像处理类库 java常用图像处理类库
    Atitit 图像处理--图像分类 模式识别 肤色检测识别原理 与attilax的实践总结
    Atitit apache 和guava的反射工具
    atitit。企业的价值观 员工第一 vs 客户第一.docx
  • 原文地址:https://www.cnblogs.com/gzdlh/p/8099219.html
Copyright © 2011-2022 走看看