• Java实现多线程的两种方式比较及区别


    Java实现多线程的两种方式比较及区别

        Java实现多线程的方式:2种
    
        方式1:自定义类继承Thread类
            1:自定义类MyThread继承Thread类
            2:MyThread类里面重写run()方法
            3:在测测试类MyThreadTest中创建MyThread类的对象
            4:启动线程
    
        方式2:自定义类实现Runnable接口
            1:自定义类MyRunnable实现Runnable接口
            2:MyRunnable类里面重写run()方法
            3:在测测试类MyRunnableTest中创建MyRunnable类的对象
            4;在测测试类MyRunnableTest中再创建Thread类的对象,并把3步骤的对象作为构造参数进行传递
            5:启动线程
            
        问题:
            1:为什么要重写run()方法?
                答:run()方法里面封装的是被线程执行的代码。
            2:启动线程对象用的是哪个方法?
                答:start()方法
            3:run()方法和start()方法的区别?
                答:run()方法直接调用仅仅是普通方法。
             start()方法是先启动线程,再由jvm去调用run()方法。
    4:有了方式1,为什么还来一个方式2呢? 答:若自定义类MyThread类已经有一个父类了,那么它就不可以再去继承Thread类了。(java不支持多继承) 若自定义类MyRunnable类已经实现了一个接口了,那么它还可以再去实现Runnable接口。(java支持多实现) 即可以避免由于Java单继承带来的局限性。 在测试类MyThreadTest中,要想开多个线程,就要先new多个自定义类MyThread的对象,每一个自定义类MyThread的对象的成员变量都相同,这样需要在栈中开辟很多内存; 在测试类MyRunnableTest中,要想开多个线程,只需要new一个自定义类MyRunnable的对象,再new多个Thread类的对象即可,这样就大大节约了内存。 即适合多个相同程序的代码去处理同一个资源的情况,把线程同程序的代码和数据有效分离(即耦合性降低),较好的体现了Java面向对象的设计思想。

    注意:图片中 1:为什么药重写run()方法?有个错别字药,应该为要。

    示例代码如下:

    方式1:自定义类继承Thread类

     1 package cn.itcast_02;
     2 
     3 /*
     4  * 该自定义的类为什么要重写run()方法?
     5  *         自定义类中不是所有的代码都需要被线程执行。
     6  *         而这个时候,为了区分哪些代码能够被线程执行,java提供了Thread类中的run()方法,用来包含那些需要被线程执行的代码。
     7  * 
     8  *         注意:这里的  被线程执行 = 开一个新线程执行
     9  */
    10 public class MyThread extends Thread {
    11     // 不需要被线程执行的代码
    12     public void show() {
    13         System.out.println("不需要被线程执行的代码"); // 这么简单的程序去开一个新的线程,纯属浪费啊!
    14     }
    15     
    16     // 需要被线程执行的代码
    17     @Override
    18     public void run() {
    19         // System.out.println("好好学习,天天向上"); // 这么简单的程序去开一个新的线程,纯属浪费啊!
    20         
    21         // 一般来说,被线程执行的代码肯定是比较耗时的。
    22         // 所以这里示例:我们使用循环
    23         for (int x = 0; x < 1000; x++) {
    24             System.out.println(x);
    25         }
    26     }
    27 
    28 }
    MyThread.java
     1 package cn.itcast_02;
     2 
     3 /*
     4  * 需求:我们要实现多线程的程序。
     5  * 
     6  * 如何通过java程序来实现多线程的程序呢?
     7  *         由于线程是依赖进程而存在的,所以我们应该先创建一个进程出来。
     8  *         而进程是由系统创建的,所以我们应该去调用系统功能创建一个进程。
     9  * 
    10  *         而Java是不能直接调用系统功能的,所以,我们没有办法直接实现多线程程序。
    11  *         但是呢?Java可以去调用C/C++写好的程序来间接实现多线程程序。
    12  * 
    13  *         由C/C++程序去调用系统功能去创建进程,然后由Java进行封装后,这样会产生一些类,我们通过这些类创建的对象去调用他们即可!
    14  * 
    15  *         这样我们就可以通过java程序来实现多线程程序了。
    16  * 
    17  * 那么Java提供的类是什么呢?
    18  *         Thread类
    19  *         通过查看API,我们知道了有2种方式可以实现多线程程序。
    20  *         (其实有三种方法,第三种明天讲)
    21  * 
    22  * 实现多线程程序
    23  * 方式1:继承Thread类
    24  *         是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。之后就可以分配并启动该子类的实例了。
    25  * 步骤
    26  *         A:自定义类MyThread继承Thread类
    27  *         B:MyThread类里面重写run()方法
    28  *         C:在测测试类MyThreadTest中创建MyThread类的对象
    29  *         D:启动线程
    30  */
    31 public class MyThreadTest {
    32     public static void main(String[] args) {
    33         // 在测测试类中创建自定义类的对象
    34         // MyThread my = new MyThread();
    35         // 启动线程
    36         // my.run();
    37         // my.run();
    38         
    39         // 调用run()方法为什么是单线程的呢?
    40         // 因为run()方法直接调用其实就相当于普通的方法调用,所以你看到的是单线程的效果。
    41         
    42         // 要想看到多线程的效果,就必须说说另一个方法:start()
    43         // 面试题:run()和start()的区别?
    44         // run():仅仅是封装被线程执行的代码,直接调用就是普通方法。
    45         // start():首先启动了线程,然后再由jvm去调用该线程的run()方法。
    46         
    47         // MyThread my = new MyThread();
    48         // my.start();
    49         // my.start();
    50         // IllegalThreadStateException:非法的线程状态异常
    51         // 为什么呢?因为这个相当于是my线程被调用了两次。而不是两个线程被启动。一个线程不能被多次启动。
    52 
    53         // 创建两个线程对象
    54         MyThread my1 = new MyThread();
    55         MyThread my2 = new MyThread();
    56         
    57         my1.setName("林青霞");
    58         my2.setName("刘意");
    59 
    60         my1.start();
    61         my2.start();
    62     }
    63 }
    MyThreadTest.java

    方式2:自定义类实现Runnable接口

     1 package cn.itcast_05;
     2 
     3 public class MyRunnable implements Runnable {
     4 
     5     @Override
     6     public void run() {
     7         for (int x = 0; x < 100; x++) {
     8             // 由于自定义类实现了接口,所以就不能在自定义类中直接使用Thread类的getName()方法了,但是可以间接的使用。
     9             // 间接方法:Thread.currentThread().getName()
    10             System.out.println(Thread.currentThread().getName() + ":" + x);
    11         }
    12     }
    13 
    14 }
    MyRunnable.java
     1 package cn.itcast_05;
     2 
     3 /* 
     4  * 实现多线程程序
     5  * 方式2:实现Runnable接口
     6  * 步骤:
     7  *         A:在自定义类MyRunnable实现Runnable接口
     8  *         B:MyRunnable类里面重写run()方法
     9  *         C:在测测试类MyRunnableTest中创建MyRunnable类的对象
    10  *         D:在测测试类MyRunnableTest中再创建Thread类的对象,并把C步骤的对象作为构造参数进行传递
    11  *         E:启动线程
    12  */
    13 public class MyRunnableTest {
    14     public static void main(String[] args) {
    15         // 在测测试类中创建MyRunnable类的对象
    16         MyRunnable my = new MyRunnable();
    17 
    18         // public Thread(Runnable target)
    19         // 在测测试类中再创建Thread类的对象,并把C步骤的对象作为构造参数进行传递
    20         // Thread t1 = new Thread(my);
    21         // Thread t2 = new Thread(my);
    22         // t1.setName("林青霞");
    23         // t2.setName("刘意");
    24 
    25         // Thread类的方法:
    26         // public Thread(Runnable target, String name)
    27         Thread t1 = new Thread(my, "林青霞");
    28         Thread t2 = new Thread(my, "刘意");
    29 
    30         t1.start();
    31         t2.start();
    32     }
    33 }
    MyRunnableTest.java

     

  • 相关阅读:
    redis概要学习
    http协议格式详解
    浅谈mysql
    linux常用命令
    Linux 程序管理
    认识与分析日志文件
    认识与学习bash
    例行任务管理
    软件安装的三大方法
    关于一些感慨
  • 原文地址:https://www.cnblogs.com/chenmingjun/p/8719760.html
Copyright © 2020-2023  润新知