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

    一 多线程介绍

      进程:进程指正在运行的程序。确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于

    运行过程中的程序,并且具有一定独立功能。

      线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程

    中是可以有多个线程的,这个应用程序也可以称之为多线程程序。

      简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程

    二 程序运行原理

    分时调度

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

    抢占式调度

      优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性)

    Java使用的为抢占式调度。

     1.抢占式调度详解

      大部分操作系统都支持多进程并发运行,现在的操作系统几乎都支持同时运行多个程序。比如:现在我们上课

    一边使用编辑器,一边使用录屏软件,同时还开着画图板,dos窗口等软件。此时,这些程序是在同时运行,”感觉

    这些软件好像在同一时刻运行着“。

      实际上,CPU(中央处理器)使用抢占式调度模式在多个线程间进行着高速的切换。对于CPU的一个核而言,

    某个时刻,只能执行一个线程,而 CPU的在多个线程间切换速度相对我们的感觉要快,看上去就是在同一时刻运行。

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

    三 主程序

    class Demo{
        String name;
        Demo(String name){
            this.name = name;
        }
        void show()    {
            for (int i=1;i<=10000 ;i++ ){
                System.out.println("name="+name+",i="+i);
            }
        }
    }
    
    class ThreadDemo {
        public static void main(String[] args)     {
            Demo d = new Demo("小强");
             Demo d2 = new Demo("旺财");
            d.show();        
            d2.show();
            System.out.println("Hello World!");
        }
    }

      若在上述代码中show方法中的循环执行次数很多,这时在d.show();下面的代码是不会马上执行的,并且在dos窗口会看

    到不停的输出name=小强,i=值,这样的语句。

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

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

    结束后能够执行。

      能够实现同时执行,通过Java中的多线程技术来解决该问题。

    四 Thread类

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

     

    常用方法

     

    创建新执行线程有两种方法。

      一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。创建对象,开启线程。

    run方法相当于其他线程的main方法。

      另一种方法是声明一个实现 Runnable 接口的类。该类然后实现 run 方法。然后创建Runnable的子

    类对象,传入到某个线程的构造方法中,开启线程。

    五 创建线程方式一继承Thread类

    创建线程的步骤:

      1 定义一个类继承Thread。

      2 重写run方法。

      3 创建子类对象,就是创建线程对象。

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

    测试类

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

    自定义线程类

    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);
            }
        }
    }

    1.继承Thread类原理

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

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

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

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

    ,那么只要在编写位置(run方法)中定义任务代码即可。所以进行了重写run方法动作。

    2.多线程的内存图解

      当执行线程的任务结束了,线程自动在栈内存中释放了。但是当所有的执行线程都结束了,那么进程就

    结束了。

    2.获取线程名称

       Thread.currentThread()获取当前线程对象

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

    class MyThread extends Thread {  //继承Thread
        MyThread(String name){
            super(name);
        }
        //复写其中的run方法
        public void run(){
            for (int i=1;i<=20 ;i++ ){
                System.out.println(Thread.currentThread().getName()+",i="+i);
            }
        }
    }
    class ThreadDemo {
        public static void main(String[] args)     {
            //创建两个线程任务
            MyThread d = new MyThread();
            MyThread d2 = new MyThread();
            d.run();//没有开启新线程, 在主线程调用run方法
            d2.start();//开启一个新线程,新线程调用run方法
        }
    }

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

      创建线程的另一种方法是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后创建Runnable的子类对象,

    传入到某个线程的构造方法中开启线程。

      查看Runnable接口说明文档:Runnable接口用来指定每个线程要执行的任务。包含了一个 run 的无参数抽象方法,

    需要由接口实现类重写该方法。

    接口中的方法

    Thread类构造方法

     

    创建线程的步骤。

      1、定义类实现Runnable接口。

      2、覆盖接口中的run方法。。

      3、创建Thread类的对象

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

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

    public class Demo02 {
        public static void main(String[] args) {
            //创建线程执行目标类对象
            Runnable runn = new MyRunnable();
            //将Runnable接口的子类对象作为参数传递给Thread类的构造函数
            Thread thread = new Thread(runn);
            Thread thread2 = new Thread(runn);
            //开启线程
            thread.start();
            thread2.start();
            for (int i = 0; i < 10; i++) {
                System.out.println("main线程:正在执行!"+i);
            }
        }
    }
    public class MyRunnable implements Runnable{
    
        //定义线程要执行的run方法逻辑
        @Override
        public void run() {
            
            for (int i = 0; i < 10; i++) {
                System.out.println("我的线程:正在执行!"+i);
            }
        }
    }

    1. 实现Runnable的原理

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

    run方法中。

      创建Thread类的对象,只有创建Thread类的对象才可以创建线程。线程任务已被封装到Runnable接口的run方法中,

    而这个run方法所属于Runnable接口的子类对象,所以将这个子类对象作为参数传递给Thread的构造函数,这样,线程

    对象创建时就可以明确要运行的线程的任务。

    2. 实现Runnable的好处

      第二种方式实现Runnable接口避免了单继承的局限性,所以较为常用。实现Runnable接口的方式,更加的符合面向

    对象,线程分为两部分,一部分线程对象,一部分线程任务。继承Thread类,线程对象和线程任务耦合在一起。一旦创建

    Thread类的子类对象,既是线程对象,有又有线程任务。实现runnable接口,将线程任务单独分离出来封装成对象,类型

    就是Runnable接口类型。Runnable接口对线程对象和线程任务进行解耦。

  • 相关阅读:
    loj#6433. 「PKUSC2018」最大前缀和(状压dp)
    PKUWC2019游记
    10. Regular Expression Matching
    9. Palindrome Number
    8. String to Integer (atoi)
    7. Reverse Integer
    6. ZigZag Conversion
    5. Longest Palindromic Substring
    4. Median of Two Sorted Arrays
    3. Longest Substring Without Repeating Characters
  • 原文地址:https://www.cnblogs.com/jiejava/p/13450563.html
Copyright © 2011-2022 走看看