惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

TaoSecurity Blog
TaoSecurity Blog
Jina AI
Jina AI
雷峰网
雷峰网
月光博客
月光博客
The GitHub Blog
The GitHub Blog
WordPress大学
WordPress大学
B
Blog RSS Feed
美团技术团队
C
CXSECURITY Database RSS Feed - CXSecurity.com
小众软件
小众软件
Security Latest
Security Latest
Microsoft Azure Blog
Microsoft Azure Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
C
Cybersecurity and Infrastructure Security Agency CISA
Last Week in AI
Last Week in AI
A
Arctic Wolf
Latest news
Latest news
Attack and Defense Labs
Attack and Defense Labs
I
Intezer
F
Fortinet All Blogs
罗磊的独立博客
MongoDB | Blog
MongoDB | Blog
Webroot Blog
Webroot Blog
S
Secure Thoughts
Help Net Security
Help Net Security
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
V
Visual Studio Blog
P
Proofpoint News Feed
博客园 - 【当耐特】
P
Privacy International News Feed
V
Vulnerabilities – Threatpost
Stack Overflow Blog
Stack Overflow Blog
Know Your Adversary
Know Your Adversary
云风的 BLOG
云风的 BLOG
Hacker News: Ask HN
Hacker News: Ask HN
L
LINUX DO - 最新话题
H
Help Net Security
爱范儿
爱范儿
酷 壳 – CoolShell
酷 壳 – CoolShell
S
SegmentFault 最新的问题
Forbes - Security
Forbes - Security
T
Tailwind CSS Blog
量子位
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
T
Tenable Blog
Cloudbric
Cloudbric
N
News and Events Feed by Topic
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Hugging Face - Blog
Hugging Face - Blog

博客园 - Neonuu

解决ollama官方下载过慢的问题(包含windows和linux) 使用java 命令运行包含main方法的class文件时,报 Error: Could not find or load main class Test Java8 list.stream()常用方法 IDEA整合SVN VUE,编辑详情时,列表数据也跟着改变 VUE二级联动,改变一级下拉框,清空二级下拉框 MySQL面试题 JVM原理 Linux服务器安装MariaDB数据库 jar包解压后,修改完配置文件,再还原成jar包 Java获取resources文件夹下properties配置文件 Java中synchronized,wait(),notify() Java中如何实现一个接口拥有多个实现类 JPA中getOne与findOne try catch与spring的事务回滚 Spring主动触发事务回滚 Redis五种数据类型及应用场景 Java面试题 SQL HAVING用法详解 const,var,let区别
Java中Runnable和Thread的区别(网上部分说法是错误的)
Neonuu · 2021-08-30 · via 博客园 - Neonuu

在实际工作中,我们很可能习惯性地选择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没有本质的区别,只是写法不同罢了,,这才是正确的结论,与资源共享无关!