zoukankan      html  css  js  c++  java
  • Java中Runnable和Thread的区别(网上部分说法是错误的)

    在实际工作中,我们很可能习惯性地选择Runnable或Thread之一直接使用,根本没在意二者的区别,但在面试中很多面试官会经常而且非常严肃的问出:请你解释下Runnable或Thread的区别?尤其是新手就容易上当,不知如何回答,就胡乱编一通。鄙人今天告诉你们这二者本身就没有本质区别,就是接口和类的区别。如果非要说区别,请看如下:

    1. Runnable的实现方式是实现其接口即可
    2. Thread的实现方式是继承其类
    3. Runnable接口支持多继承,但基本上用不到
    4. Thread实现了Runnable接口并进行了扩展,而Thread和Runnable的实质是实现的关系,不是同类东西,所以Runnable或Thread本身没有可比性。

      网络上流传的最大的一个错误结论:Runnable更容易可以实现多个线程间的资源共享,而Thread不可以! 这是一个错误的结论!

    我们假定一个场景,分3个窗口(线程)买10张票:

    一、实现Runnable接口

    package com.neonuu.collection.domain;
    
    public class RunnableTest {
    
    
        static class MyRunnable implements Runnable{
    
            //共购买10张票
            private int ticket = 10;
    
            @Override
            public  void run() {
                //实现Runnable接口
                for(int i=0;i<10;i++){
                    //利用synchronized锁,实现同步,防止超卖
                    synchronized(this){
                        if(this.ticket>0){
                            try {
                                System.out.println(Thread.currentThread().getName()+"购票前剩余:"+this.ticket);
                                ticket--;
                                System.out.println(Thread.currentThread().getName()+"购票后剩余:"+this.ticket);
                                System.out.println("================");
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }else {
                            break;
                        }
                    }
    
                }
            }
        }
    
    
    
        public static void main(String[] args){
            //实现Runnable接口,3个线程同时购买10张票
            MyRunnable myRunable = new MyRunnable();
            Thread myRunnable1 = new Thread(myRunable,"myRunnable1");
            Thread myRunnable2 = new Thread(myRunable,"myRunnable2");
            Thread myRunnable3 = new Thread(myRunable,"myRunnable3");
            myRunnable1.start();
            myRunnable2.start();
            myRunnable3.start();
        }
    }

    结果如下:

    myRunnable1购票前剩余:10
    myRunnable1购票后剩余:9
    ================
    myRunnable3购票前剩余:9
    myRunnable3购票后剩余:8
    ================
    myRunnable3购票前剩余:8
    myRunnable3购票后剩余:7
    ================
    myRunnable2购票前剩余:7
    myRunnable2购票后剩余:6
    ================
    myRunnable3购票前剩余:6
    myRunnable3购票后剩余:5
    ================
    myRunnable1购票前剩余:5
    myRunnable1购票后剩余:4
    ================
    myRunnable1购票前剩余:4
    myRunnable1购票后剩余:3
    ================
    myRunnable3购票前剩余:3
    myRunnable3购票后剩余:2
    ================
    myRunnable2购票前剩余:2
    myRunnable2购票后剩余:1
    ================
    myRunnable2购票前剩余:1
    myRunnable2购票后剩余:0
    ================

    二、继承Thread

    package com.neonuu.collection.domain;
    
    public class ThreadTest {
        static class MyThread extends Thread {
    
            //共购买10张票
            private int ticket = 10;
    
            public void run(){
                //继承Thread类
                for(int i=0;i<10;i++){
                    //利用synchronized锁,实现同步,防止超卖
                    synchronized(this){
                        if(this.ticket>0){
                            try {
                                System.out.println(Thread.currentThread().getName()+"购票前剩余:"+this.ticket);
                                ticket--;
                                System.out.println(Thread.currentThread().getName()+"购票后剩余:"+this.ticket);
                                System.out.println("================");
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }else {
                            break;
                        }
                    }
    
                }
            }
    
        }
    
        public static void main(String[] args){
    
            //方法一:创建3个MyThread实例
            //网上多数采用此方法,来证明Thread与Runnable在资源共享上的区别,其实是错误的
            //结果:3个线程各买了10张票,共30张票
            MyThread myThread1 = new MyThread();
            MyThread myThread2 = new MyThread();
            MyThread myThread3 = new MyThread();
            myThread1.start();
            myThread2.start();
            myThread3.start();
    
            //方法二:创建1个MyThread实例,开启3个线程
            //结果:与继承Runnable相同,3个线程同时购买10张票
            MyThread myThread = new MyThread();
            Thread myThread4 = new Thread(myThread,"myThread1");
            Thread myThread5 = new Thread(myThread,"myThread2");
            Thread myThread6 = new Thread(myThread,"myThread3");
            myThread4.start();
            myThread5.start();
            myThread6.start();
    
        }
    }

    在main方法中我们使用两种写法

    1、方法一的结果:

    Thread-0购票前剩余:10
    Thread-0购票后剩余:9
    Thread-2购票前剩余:10
    Thread-1购票前剩余:10
    Thread-2购票后剩余:9
    ================
    ================
    Thread-1购票后剩余:9
    ================
    Thread-1购票前剩余:9
    Thread-0购票前剩余:9
    Thread-2购票前剩余:9
    Thread-1购票后剩余:8
    ================
    Thread-2购票后剩余:8
    ================
    Thread-0购票后剩余:8
    ================
    Thread-0购票前剩余:8
    Thread-0购票后剩余:7
    ================
    Thread-2购票前剩余:8
    Thread-2购票后剩余:7
    ================
    Thread-1购票前剩余:8
    Thread-1购票后剩余:7
    ================
    Thread-2购票前剩余:7
    Thread-0购票前剩余:7
    Thread-1购票前剩余:7
    Thread-0购票后剩余:6
    ================
    Thread-1购票后剩余:6
    ================
    Thread-2购票后剩余:6
    ================
    Thread-0购票前剩余:6
    Thread-2购票前剩余:6
    Thread-1购票前剩余:6
    Thread-2购票后剩余:5
    ================
    Thread-0购票后剩余:5
    ================
    Thread-1购票后剩余:5
    ================
    Thread-1购票前剩余:5
    Thread-1购票后剩余:4
    ================
    Thread-0购票前剩余:5
    Thread-0购票后剩余:4
    ================
    Thread-2购票前剩余:5
    Thread-2购票后剩余:4
    ================
    Thread-2购票前剩余:4
    Thread-2购票后剩余:3
    ================
    Thread-0购票前剩余:4
    Thread-0购票后剩余:3
    ================
    Thread-1购票前剩余:4
    Thread-1购票后剩余:3
    ================
    Thread-1购票前剩余:3
    Thread-1购票后剩余:2
    ================
    Thread-0购票前剩余:3
    Thread-0购票后剩余:2
    ================
    Thread-2购票前剩余:3
    Thread-2购票后剩余:2
    ================
    Thread-2购票前剩余:2
    Thread-2购票后剩余:1
    ================
    Thread-0购票前剩余:2
    Thread-0购票后剩余:1
    ================
    Thread-1购票前剩余:2
    Thread-1购票后剩余:1
    ================
    Thread-2购票前剩余:1
    Thread-2购票后剩余:0
    ================
    Thread-0购票前剩余:1
    Thread-0购票后剩余:0
    ================
    Thread-1购票前剩余:1
    Thread-1购票后剩余:0
    ================

    可以看出,方法一分三个线程分别购买了10张票,共购买了30张。这个结果并不是我们想要的。网上大部分是通过这个来证明Thread不能资源共享,是错误的!

    2、方法二的结果

    myThread1购票前剩余:10
    myThread1购票后剩余:9
    ================
    myThread3购票前剩余:9
    myThread3购票后剩余:8
    ================
    myThread2购票前剩余:8
    myThread2购票后剩余:7
    ================
    myThread3购票前剩余:7
    myThread3购票后剩余:6
    ================
    myThread1购票前剩余:6
    myThread1购票后剩余:5
    ================
    myThread3购票前剩余:5
    myThread3购票后剩余:4
    ================
    myThread2购票前剩余:4
    myThread2购票后剩余:3
    ================
    myThread3购票前剩余:3
    myThread3购票后剩余:2
    ================
    myThread1购票前剩余:2
    myThread1购票后剩余:1
    ================
    myThread1购票前剩余:1
    myThread1购票后剩余:0
    ================

    可以看出,这个结果与Runnable是相同的,3个线程共同购买10张票

    注:synchronized这个关键字是必须的,否则会发生超买,买了11张票,ticket变为负数。

    三、结论:

    事实是Thread和Runnable没有本质的区别,只是写法不同罢了,,这才是正确的结论,与资源共享无关!

  • 相关阅读:
    接口测试--apipost中cookie管理器的使用
    python解释器换了路径,导致pip安装失败解决方法
    Jmeter之Bean shell使用(二)
    Jmeter之Bean shell使用(一)
    BeanShell生成随机数
    Jmeter之Json 提取器
    Jmeter全面信息学习笔记
    python模块之codecs
    open()和with open()的区别
    【图像处理】第二次实验:二维快速傅里叶变换与离散余弦变换
  • 原文地址:https://www.cnblogs.com/Neonuu/p/15204615.html
Copyright © 2011-2022 走看看