• java学习笔记 --- 多线程(多线程的创建方式)


    1、创建多线程方式1——继承Thread类。
       步骤:
           A:自定义类MyThread继承Thread类。
           B:MyThread类里面重写run()?
              为什么是run()方法呢?
           C:创建对象
           D:启动线程

    /* 方式1:继承Thread类。
     * 步骤
     *         A:自定义类MyThread继承Thread类。
     *         B:MyThread类里面重写run()?
     *             为什么是run()方法呢?
     *         C:创建对象
     *         D:启动线程
     */
     public class MyThread extends Thread {//继承Thread类
    
    /* 该类要重写run()方法,为什么呢?
     * 不是类中的所有代码都需要被线程执行的。
     * 而这个时候,为了区分哪些代码能够被线程执行,java提供了Thread类中的run()用来 包含那些被线程执行的代码。
     */
    
        @Override
        public void run() {
            // 自己写代码
            // System.out.println("好好学习,天天向上");
            // 一般来说,被线程执行的代码肯定是比较耗时的。所以我们用循环改进
            for (int x = 0; x < 200; x++) {
                System.out.println(x);
            }
        }
    
    }
    public class MyThreadDemo {
        public static void main(String[] args) {
            // 创建线程对象
            // MyThread my = new MyThread();
            // // 启动线程
            // my.run();
            // my.run();
            // 调用run()方法为什么是单线程的呢?
            // 因为run()方法直接调用其实就相当于普通的方法调用,所以你看到的是单线程的效果
            // 要想看到多线程的效果,就必须说说另一个方法:start()
            // 面试题:run()和start()的区别?
            // run():仅仅是封装被线程执行的代码,直接调用是普通方法
            // start():首先启动了线程,然后再由jvm去调用该线程的run()方法。
            // MyThread my = new MyThread();
            // my.start();
            // // IllegalThreadStateException:非法的线程状态异常
            // // 为什么呢?因为这个相当于是my线程被调用了两次。而不是两个线程启动。
            // my.start();
    
            // 创建两个线程对象
            MyThread my1 = new MyThread();
            MyThread my2 = new MyThread();
    
            my1.start();
            my2.start();
        }
    }

    2、线程对象调用 run方法和调用start方法区别?

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

    3、为什么要重写run()方法?(和代码中注释的一个意思)

    自定义线程需要执行的任务都定义在run方法中。Thread类中的run方法内部的任务并不是我们所需要,只有重写这个run方法,既然Thread类已经定义了线程任务的位置,只要在位置中定义任务代码即可。所以进行了重写run方法动作。

    4、获取线程名称

    public class MyThread extends Thread {//继承Thread内
        
             
        public MyThread() {
        }
        
        public MyThread(String name){
            super(name);
        }
            //重写run()方法
        @Override
        public void run() {
            for (int x = 0; x < 100; x++) {
                System.out.println(getName() + ":" + x);
            }
        }
    }
    /*
     * 如何获取线程对象的名称呢?
     * public final String getName():获取线程的名称。
     * 如何设置线程对象的名称呢?
     * public final void setName(String name):设置线程的名称
     * 
     * 针对不是Thread类的子类中如何获取线程对象名称呢?
     * public static Thread currentThread():返回当前正在执行的线程对象
     * Thread.currentThread().getName()
     */
    public class MyThreadDemo {
        public static void main(String[] args) {
            // 创建线程对象
            //无参构造+setXxx()
            // MyThread my1 = new MyThread();
            // MyThread my2 = new MyThread();
            // //调用方法设置名称
            // my1.setName("线程1");
            // my2.setName("线程2");
            // my1.start();
            // my2.start();
            
            //带参构造方法给线程起名字
            // MyThread my1 = new MyThread("线程1");
            // MyThread my2 = new MyThread("线程2");
            // my1.start();
            // my2.start();
            
            //我要获取main方法所在的线程对象的名称,该怎么办呢?
            //遇到这种情况,Thread类提供了一个很好玩的方法:
            //public static Thread currentThread():返回当前正在执行的线程对象
            System.out.println(Thread.currentThread().getName());
        }
    }

    5、创建多线程的方法2——实现Runnable接口

      步骤:
           A:自定义类MyRunnable实现Runnable接口
           B:重写接口中的run()方法
           C:创建MyRunnable类的对象
           D:创建Thread类的对象,并把C步骤的对象作为构造参数传递

    /*
     * 方式2:实现Runnable接口
     * 步骤:
     *         A:自定义类MyRunnable实现Runnable接口
     *         B:重写run()方法
     *         C:创建MyRunnable类的对象
     *         D:创建Thread类的对象,并把C步骤的对象作为构造参数传递
     */
    
    public class MyRunnable implements Runnable {//步骤一:自定义类实现Runnable接口
    
        @Override
        public void run() {//重写run()方法
            for (int x = 0; x < 100; x++) {
                // 由于实现接口的方式就不能直接使用Thread类的方法了,但是可以间接的使用
                System.out.println(Thread.currentThread().getName() + ":" + x);
            }
        }
    
    public class MyRunnableDemo {
        public static void main(String[] args) {
            // 创建MyRunnable类的对象
            MyRunnable my = new MyRunnable();
    
            // 创建Thread类的对象,并把C步骤的对象作为构造参数传递
            // Thread(Runnable target)
            // Thread t1 = new Thread(my);
            // Thread t2 = new Thread(my);
            // t1.setName("线程1");
            // t2.setName("线程2");
    
            // Thread(Runnable target, String name)
            Thread t1 = new Thread(my, "线程1");
            Thread t2 = new Thread(my, "线程2");
    
            t1.start();
            t2.start();
        }
    }

    6、实现Runnable的原理

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

         实现Runnable接口,避免了继承Thread类的单继承局限性。覆盖Runnable接口中的run方法,将线程任务代码定义到run方法中。创建Thread类的对象,只有创建Thread类的对象才可以创建线程。线程任务已被封装到Runnable接口的run方法中,而这个run方法所属于Runnable接口的子类对象,所以将这个子类对象作为参数传递给Thread的构造函数,这样,线程对象创建时就可以明确要运行的线程的任务。

    7、实现Runnable的好处

      第二种方式实现Runnable接口避免了单继承的局限性,所以较为常用。实现Runnable接口的方式,更加的符合面向对象,线程分为两部分,一部分线程对象,一部分线程任务。继承Thread类,线程对象和线程任务耦合在一起。一旦创建Thread类的子类对象,既是线程对象,有又有线程任务。实现runnable接口,将线程任务单独分离出来封装成对象,类型就是Runnable接口类型。Runnable接口对线程对象和线程任务进行解耦。

  • 相关阅读:
    关于web前端网站优化
    C/S与B/S架构的区别和优缺点
    什么是闭包?闭包的优缺点?
    JavaScript中基本数据类型和引用数据类型的区别
    jQuery对象与DOM对象之间的转换方法
    (转)第05节:Fabric.js的动画设置
    (转)第04节:Fabric.js用路径画不规则图形
    layui表单与原生js表单的一些小问题(三)
    layui表单与原生js表单的一些小问题(二)
    layui表单与原生js表单的一些小问题(一)
  • 原文地址:https://www.cnblogs.com/flei/p/6622561.html
Copyright © 2020-2023  润新知