zoukankan      html  css  js  c++  java
  • Java基础学习总结 -- 多线程的实现

    目录:

      多线程的实现方法:

        继承Thread类

        实现Runnable接口

      -------------------------------------------------------------------------------------

      1. 继承Thread类

        继承Thread类之后,需要覆盖父类的 public void run() 方法,作为线程的主方法。

        所有线程的执行一定是并发的,即:同一个时间段上会有多个线程交替执行。为了达到这样的目的,绝对不能直接调用run()方法,而是应该调用Thread类的start()方法启动多线程。

        调用 start() 方法和调用 run() 方法的对比:

    public class MyThread extends Thread {
        private String name;
        public MyThread(String name) {
            this.name = name;
        }
        
        @Override
        public void run() {
            for(int i=0; i<10; i++) {
            System.out.println(name + "打印:" + i);
            }
        }
        
        public static void main(String[] args) {
            MyThread mt1 = new MyThread("线程A");
            MyThread mt2 = new MyThread("线程B");
            MyThread mt3 = new MyThread("线程C");
            mt1.start();
            mt2.start();
            mt3.start();
        }
    }

      运行结果:(三个线程同时且交替执行,没有固定的执行顺序)

       

    public class MyThread extends Thread {
        private String name;
        public MyThread(String name) {
            this.name = name;
        }
        
        @Override
        public void run() {
            for(int i=0; i<5; i++) {
            System.out.println(name + "打印:" + i);
            }
        }
        
        public static void main(String[] args) {
            MyThread mt1 = new MyThread("线程A");
            MyThread mt2 = new MyThread("线程B");
            MyThread mt3 = new MyThread("线程C");
            mt1.run();
            mt2.run();
            mt3.run();
        }
    }

      运行结果:(三个程序依次顺序执行)

       

      2. start()方法实现多线程的原理

        打开Thread类源代码中start()方法的部分:

    public synchronized void start() {
            if (threadStatus != 0)
                throw new IllegalThreadStateException();
            group.add(this);
            boolean started = false;
            try {
                start0();
                started = true;
            } finally {
                try {
                    if (!started) {
                        group.threadStartFailed(this);
                    }
                } catch (Throwable ignore) {
                }
            }
    }
    private native void start0();

        native关键字是指调用操作系统的方法,start0()方法是所在操作系统的方法。

        由于线程的启动需要牵扯到操作系统中资源的分配问题,所以具体的线程的启动应该根据不同的操作系统有不同的实现。而JVM根据不同的操作系统中定义的start0()方法进行不同的实现。这样,在多线程的层次上start0()方法的名称不改变,而不同的操作系统有不同的实现。

    原理图

        结论:只有Thread类的start()方法才能进行操作系统资源的分配,所以启动多线程的方式永远就是Thread类的start()方法。

     

      3. 实现Runnable接口

        一般使用这种方式来实现多线程,因为这样可以避免继承Thread类的单继承局限

    package test;
    
    public class MyThread implements Runnable {
        private String name;
        public MyThread(String name) {
            this.name = name;
        }
        
        @Override
        public void run() {
            for(int i=0; i<5; i++) {
            System.out.println(name + "打印:" + i);
            }
        }
        
        public static void main(String[] args) {
            MyThread mt1 = new MyThread("线程A");
            MyThread mt2 = new MyThread("线程B");
            MyThread mt3 = new MyThread("线程C");
            new Thread(mt1).start();
            new Thread(mt2).start();
            new Thread(mt3).start();
        }
    }

      4. Thread类 与 Runnable接口 的联系与区别

        联系

          Thread类是实现了Runnable接口的类。

          

        区别

          Runnable接口实现的多线程要比Thread类实现的多线程更方便的表示出数据共享的概念。

          范例:希望有三个线程进行卖票

    //使用Thread类实现
    
    public class MyThread extends Thread {
        private String name;
        int tickets = 5;
        
        public MyThread(String name) {
            this.name = name;
        }
        
        @Override
        public void run() {
            while(tickets>0) {
                System.out.println(name + "买票出一张票,剩余票数:" + (--tickets));
            }
        }
        
        public static void main(String[] args) {
            MyThread mt1 = new MyThread("线程A");
            MyThread mt2 = new MyThread("线程B");
            MyThread mt3 = new MyThread("线程C");
            mt1.start();
            mt2.start();
            mt3.start();
        }
    }
    
    /*
    线程C买票出一张票,剩余票数:4
    线程A买票出一张票,剩余票数:4
    线程B买票出一张票,剩余票数:4
    线程A买票出一张票,剩余票数:3
    线程C买票出一张票,剩余票数:3
    线程A买票出一张票,剩余票数:2
    线程B买票出一张票,剩余票数:3
    线程A买票出一张票,剩余票数:1
    线程C买票出一张票,剩余票数:2
    线程C买票出一张票,剩余票数:1
    线程A买票出一张票,剩余票数:0
    线程B买票出一张票,剩余票数:2
    线程B买票出一张票,剩余票数:1
    线程B买票出一张票,剩余票数:0
    线程C买票出一张票,剩余票数:0
    */
    //使用Runnable接口实现
    
    public class MyThread implements Runnable {
        int tickets = 5;
        
        @Override
        public void run() {
            while(tickets>0) {
                System.out.println(Thread.currentThread().getName() + "买票出一张票,剩余票数:" + (--tickets));
            }
        }
        
        public static void main(String[] args) {
            MyThread mt = new MyThread();
            new Thread(mt,"线程A").start();
            new Thread(mt,"线程B").start();
            new Thread(mt,"线程C").start();
        }
    }
    
    /*
    线程B买票出一张票,剩余票数:3
    线程A买票出一张票,剩余票数:4
    线程C买票出一张票,剩余票数:2
    线程A买票出一张票,剩余票数:0
    线程B买票出一张票,剩余票数:1
    */
    //同一个线程不能重复启动,否则会出现异常
    
    public class MyThread extends Thread {
        int tickets = 5;
        
        @Override
        public void run() {
            while(tickets>0) {
                System.out.println("买票出一张票,剩余票数:" + (--tickets));
            }
        }
        
        public static void main(String[] args) {
            MyThread mt = new MyThread();
            mt.start();
            mt.start();
            mt.start();
        }
    }
    
    /*
    Exception in thread "main" 买票出一张票,剩余票数:4
    买票出一张票,剩余票数:3
    买票出一张票,剩余票数:2
    买票出一张票,剩余票数:1
    买票出一张票,剩余票数:0
    java.lang.IllegalThreadStateException
        at java.lang.Thread.start(Unknown Source)
        at test.MyThread.main(MyThread.java:17)
    */

        图释:

       

    使用Thread类的内存情况

       

    使用Runnable接口的内存情况

      面试题:请解释多线程的两种实现方式以及区别,并用代码验证?

        答:多线程需要一个线程的主类,这个类要么继承Thread类,要么实现Runnable接口;

          使用Runnable接口要比Thread类更好地实现数据共享的操作,并且使用Runnable接口可以避免单继承局限。

          代码如上。

     

     

     

     

  • 相关阅读:
    Spring2.5.6学习笔记DI的两种注入方式
    hsqldb2.2.9文档学习笔记之使用hsqldb
    Spring2.5.6学习笔记实例化bean的几种方法
    eclipse4.2插件开发之Hello!EclipsePlugin
    spring boot redis 多数据源配置 spring boot data redis
    docker安装mysql
    docker安装rabbitmq
    docker命令积累
    mysql8 免安装版 下载安装
    docker安装nginx
  • 原文地址:https://www.cnblogs.com/xingyazhao/p/6083638.html
Copyright © 2011-2022 走看看