昨天去面试,面试官问了一个问题:Runnable和Thread有什么区别,因为针对这个问题以前有背过,并且网上大多数都是这些结论,所以脱口而出:

1.Thread有单继承的问题;
2.Runnable便于实现资源共享,而Thread不能;

然而面试官好像并没有什么表示。之后结束后我就找了一下度娘,得到了这篇文章:

https://blog.csdn.net/zhaojianting/article/details/97664370

突然发现“Runnable便于实现资源共享”这一优点好像并不合理,以下是我的代码实现。

使用Thread实现多线程

public class MyThread extends Thread {

    private int ticket = 5;

    @Override
public void run() {
while (true) {
System.out.println("Thread ticket = " + ticket--);
if (ticket < 0) {
break;
}
}
} } public class Test {
public static void main(String[] args) { //Test Thread new MyThread().start();
new MyThread().start(); }
} 执行结果如下:
Thread ticket = 5
Thread ticket = 4
Thread ticket = 3
Thread ticket = 2
Thread ticket = 1
Thread ticket = 0
Thread ticket = 5
Thread ticket = 4
Thread ticket = 3
Thread ticket = 2
Thread ticket = 1
Thread ticket = 0

并不能实现资源共享,跟以前背的面试题答案一样;但真的是这样吗?我们仔细看一下,代码中我们创建了两个MyThread对象,每个对象都有自己的ticket成员变量,当然会多卖1倍。现在我们重新测试一下,请看测试代码:

public class Test {
public static void main(String[] args) { //Test Thread MyThread t1 = new MyThread();
new Thread(t1).start();
new Thread(t1).start();
}
} 测试结果如下:
Thread ticket = 5
Thread ticket = 4
Thread ticket = 3
Thread ticket = 2
Thread ticket = 1
Thread ticket = 0
Thread ticket = -1

可以看到这次我们只创建了一个MyThread对象,并没出现卖两倍票的情况,Thread也可以实现资源共享。

因为多线程访问同一变量会有并发问题(需要加锁),所以Thread正确的写法如下:

public class MyThread extends Thread {

    private int ticket = 5;

    @Override
public void run() {
if (ticket > 0) {
synchronized (this) {
if (ticket > 0) {
while (true) {
System.out.println("Thread:" + Thread.currentThread().getName() + "--Thread ticket = " + ticket--);
if (ticket < 0) {
break;
}
}
}
}
}
} } public class Test {
public static void main(String[] args) { //Test Thread MyThread t1 = new MyThread();
new Thread(t1).start();
new Thread(t1).start();
new Thread(t1).start();
new Thread(t1).start();
new Thread(t1).start();
new Thread(t1).start();
}
} 执行结果如下:
Thread:Thread-1--Thread ticket = 5
Thread:Thread-1--Thread ticket = 4
Thread:Thread-1--Thread ticket = 3
Thread:Thread-1--Thread ticket = 2
Thread:Thread-1--Thread ticket = 1
Thread:Thread-1--Thread ticket = 0

现在看Thread和Runnable的源码:


public
class Thread implements Runnable {
/* Make sure registerNatives is the first thing <clinit> does. */
private static native void registerNatives();
static {
registerNatives();
} private volatile String name;
private int priority;
private Thread threadQ;
private long eetop; @FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}

结论:其实Thread也就是实现了Runnable接口,提供了更多的方法而已。所以说Thread与Runnable并没有什么区别。如果硬要说有什么区别的话,那就是类与接口的区别,继承与实现的区别。另外最重要的是,学习的时候不要忘了思考哦!

彻底理解Runnable和Thread的区别的更多相关文章

  1. Java中Runnable和Thread的区别

    在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口:Thread类是在java.lang包中定义的.一个类只要继承了Thread类同时覆写了本类中的run() ...

  2. Android笔记——Handler Runnable与Thread的区别

    在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口:Thread类是在java.lang包中定义的.一个类只要继承了Thread类同时覆写了本类中的run() ...

  3. Android开发笔记之:Handler Runnable与Thread的区别详解

    在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口:Thread类是在java.lang包中定义的.一 个类只要继承了Thread类同时覆写了本类中的run( ...

  4. Runnable和Thread的区别 (转)

    在java中可有两种方式实现多线程,一种是继承 Thread类,一种是实现Runnable接口:Thread类是在java.lang包中定义的.一个类只要继承了Thread类同时覆写了本类中的 run ...

  5. 【转】java线程系列---Runnable和Thread的区别

    在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口:Thread类是在java.lang包中定义的.一个类只要继承了Thread类同时覆写了本类中的run() ...

  6. java线程系列---Runnable和Thread的区别 (转载)

    转自:http://blog.csdn.net/wwww1988600/article/details/7309070 在java中可有两种方式实现多线程,一种是继承 Thread类,一种是实现Run ...

  7. Java中Runnable和Thread的区别(转)

    http://developer.51cto.com/art/201203/321042.htm 第一种方式:使用Runnable接口创建线程 第二种方式:直接继承Thread类创建对象 使用Runn ...

  8. runnable和thread的区别

    一是写一个类继承自Thread类,然后重写里面的run方法,用start方法启动线程二是写一个类实现Runnable接口,实现里面的run方法,用new Thread(Runnable target) ...

  9. Runnable和Thread区别和比较

    在很多博客中用这样一个例子来说明 Runnable更容易实现资源共享,能多个线程同时处理一个资源. 看代码: public static void main(String[] args) { new ...

随机推荐

  1. Hibernate——离线查询

    1.Criteria查询方式: (1)一般方式: 缺点:每一次查询dao层都需要书写对应的方法,离线查询可以解决这个问题. (2)离线方式: 2.离线查询 用DetachedCriteria来构造查询 ...

  2. 第04组Alpha事后诸葛亮

    一.组长博客:地址 二.Postmortem模板 设想和目标 1.我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 我们要解决的问题是让大学生可以通过福鱼网站将暂时无 ...

  3. Tomcat8.x的安装与启动

    Tomcat是企业网站的服务器,大多都用于中.小型网站开发和学习开发JSP应用程序中.笔者也是开始学习,下面介绍Tomcat8.x的安装步骤. 进入Tomcat官网,点击左边的download目录下的 ...

  4. gitlab 从古老的 bitnami 版本 迁移到官方最新版本

    这是我之前发布在 yuque 的文章.是我刚来新公司的时候帮公司搬迁 git 记录下来的,现在看来去掉敏感部分直接发布也没啥问题啦,就搬家过来,我自己也方便查 XD . 8.1.6 -> 10. ...

  5. MVC方法返回值数据

    ModelAndView的作用以及用法 使用ModelAndView类用来存储处理完后的结果数据,以及显示该数据的视图.从名字上看ModelAndView中的Model代表模型,View代表视图,这个 ...

  6. go语言Mac下编译安装语言包

    这两天公司成立了go语言学习兴趣小组,慕名参与了学习.目前对于go是0基础,只知道它可以做高并发.效率快.编译简单.母语是C. go的安装有多种形式,编译安装是比较慢的一个,今天我就记录一下学习go编 ...

  7. Linux 查看文件权限命令ls -l 输出信息每列所代表的含义

  8. Mercurial 的hook使用

    1. Handling repository events with hooks可以通过Mercurial版本管理工具提供的hooks机制来处理repo的各种事件,从而实现对Mercurial的扩展, ...

  9. Fluent——UDF监测指定点的物理量

    Fluent版本:19.0 Fluent当中提供了监测某一点物理量随迭代次数或者随时间变化的功能,下面我们就介绍如何在UDF当中实现相同的功能,并且UDF更加灵活,通过UDF的方式我们在知道某点运动规 ...

  10. iptables只允许指定ip访问本机的指定端口

    首先,清除所有预设置 iptables -F 其次,设置只允许指定ip地址访问指定端口 1.在tcp协议中,禁止所有的ip访问本机的1521端口. iptables -I INPUT -p tcp - ...