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

推荐订阅源

V
Vulnerabilities – Threatpost
U
Unit 42
F
Fortinet All Blogs
aimingoo的专栏
aimingoo的专栏
P
Proofpoint News Feed
F
Full Disclosure
月光博客
月光博客
Engineering at Meta
Engineering at Meta
博客园_首页
The Register - Security
The Register - Security
G
Google Developers Blog
The Cloudflare Blog
博客园 - Franky
K
Kaspersky official blog
A
Arctic Wolf
Scott Helme
Scott Helme
C
Cisco Blogs
Hugging Face - Blog
Hugging Face - Blog
C
Check Point Blog
NISL@THU
NISL@THU
AI
AI
D
DataBreaches.Net
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Stack Overflow Blog
Stack Overflow Blog
Project Zero
Project Zero
The GitHub Blog
The GitHub Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
量子位
Vercel News
Vercel News
T
Tor Project blog
P
Privacy International News Feed
D
Docker
I
Intezer
L
LangChain Blog
P
Proofpoint News Feed
Security Latest
Security Latest
C
CXSECURITY Database RSS Feed - CXSecurity.com
T
Threatpost
博客园 - 聂微东
AWS News Blog
AWS News Blog
Martin Fowler
Martin Fowler
P
Privacy & Cybersecurity Law Blog
V
V2EX
Last Week in AI
Last Week in AI
C
Cybersecurity and Infrastructure Security Agency CISA
The Hacker News
The Hacker News
T
Tenable Blog
Blog — PlanetScale
Blog — PlanetScale
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Tailwind CSS 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没有本质的区别,只是写法不同罢了,,这才是正确的结论,与资源共享无关!