Java 多线程实现接口Runnable和继承Thread区别

Java中有两种实现多线程的方式。一是直接继承Thread类,二是实现Runnable接口。那么这两种实现多线程的方式在应用上有什么区别呢?

网上流传很广的是一个网上售票系统

为了回答这个问题,我们可以通过讲解编写一段代码来进行分析。我们用代码来模拟铁路售票系统,实现通过四个售票点发售某日某次列车的100张车票,一个售票点用一个线程表示。

下面是  继承Thread类实现的过程:

 public class ThreadTest extends Thread{
private int ticket = 100;
public void run(){
while(true){
if(ticket > 0){
System.out.println(Thread.currentThread().getName() + "is selling ticket" + ticket--);
}else{
break;
}
}
}
}

main测试类:

public class ThreadDome1{
public static void main(String[] args){
ThreadTest t = new ThreadTest();
t.start();
t.start();
t.start();
t.start();
}
}

上面的代码中,我们用ThreadTest类模拟售票处的售票过程,run方法中的每一次循环都将总票数减1,模拟卖出一张车票,同时该车票号打印出来,直接剩余的票数到零为止。在ThreadDemo1类的main方法中,我们创建了一个线程对象,并重复启动四次,希望通过这种方式产生四个线程。从运行的结果来看我们发现其实只有一个线程在运行,这个结果告诉我们:一个线程对象只能启动一个线程,无论你调用多少遍start()方法,结果只有一个线程。

我们接着修改ThreadDemo1,在main方法中创建四个Thread对象:

public class ThreadDemo1{
public static void main(String[] args){
new ThreadTest().start();
new ThreadTest().start();
new ThreadTest().start();
new ThreadTest().start();
}
}
class ThreadTest extends Thread{
private int ticket = ;
public void run(){
while(true){
if(ticket > ){
System.out.println(Thread.currentThread().getName() + " is selling ticket" + ticket--);
}else{
break;
}
}
}
}

这下达到目的了吗?

从结果上看每个票号都被打印了四次,即四个线程各自卖各自的100张票,而不去卖共同的100张票。这种情况是怎么造成的呢?我们需要的是,多个线程去处理同一个资源,一个资源只能对应一个对象,在上面的程序中,我们创建了四个ThreadTest对象,就等于创建了四个资源,每个资源都有100张票,每个线程都在独自处理各自的资源。

经过这些实验和分析,可以总结出,要实现这个铁路售票程序,我们只能创建一个资源对象,但要创建多个线程去处理同一个资源对象,并且每个线程上所运行的是相同的程序代码。

在回顾一下使用接口编写多线程的过程:

public class ThreadDemo1{
public static void main(String[] args){
ThreadTest t = new ThreadTest();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
}
} class ThreadTest implements Runnable{
private int tickets = ;
public void run(){
while(true){
if(tickets > ){
System.out.println(Thread.currentThread().getName() + " is selling ticket " + tickets--);
}
}
}
}

上面的程序中,创建了四个线程,每个线程调用的是同一个ThreadTest对象中的run()方法,访问的是同一个对象中的变量(tickets)的实例,这个程序满足了我们的需求。在Windows上可以启动多个记事本程序一样,也就是多个进程使用同一个记事本程序代码。

可见,实现Runnable接口相对于继承Thread类来说,有如下显著的好处:

(1)适合多个相同程序代码的线程去处理同一资源的情况,把虚拟CPU(线程)同程序的代码,数据有效的分离,较好地体现了面向对象的设计思想。

(2)可以避免由于Java的单继承特性带来的局限。我们经常碰到这样一种情况,即当我们要将已经继承了某一个类的子类放入多线程中,由于一个类不能同时有两个父类,所以不能用继承Thread类的方式,那么,这个类就只能采用实现Runnable接口的方式了。

(3)有利于程序的健壮性,代码能够被多个线程共享,代码与数据是独立的。当多个线程的执行代码来自同一个类的实例时,即称它们共享相同的代码。多个线程操作相同的数据,与它们的代码无关。当共享访问相同的对象是,即它们共享相同的数据。当线程被构造时,需要的代码和数据通过一个对象作为构造函数实参传递进去,这个对象就是一个实现了Runnable接口的类的实例。

Java 多线程实现接口Runnable和继承Thread区别(转)的更多相关文章

  1. Java 多线程实现方式一:继承Thread类

    java 通过继承Thread类实现多线程很多简单: 只需要重写run方法即可. 比如我们分三个线程去京东下载三张图片: 1.先写个下载类: 注意导入CommonsIO 包 public class ...

  2. Java多线程中的Runnable和Thread

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

  3. Java之同步代码块处理继承Thread类的线程安全问题

    package com.atguigu.java; /** *//** * 使用同步代码块解决继承Thread类的方式的线程安全问题 * * 例子:创建三个窗口卖票,总票数为100张.使用继承Thre ...

  4. 在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口

    //继承thread类 class PrimeThread extends Thread{ long minPrime; PrimeThread(long minPrime) { this.minPr ...

  5. Java多线程高并发学习笔记(一)——Thread&Runnable

    进程与线程 首先来看百度百科关于进程的介绍: 进程是一个具有独立功能的程序关于某个数据集合的一次运行活动.它可以申请和拥有系统资源,是一个动态的概念,是一个活动的实体.它不只是程序的代码,还包括当前的 ...

  6. java多线程(二)-Runnable和Thread

    Java在顺序性语言的基础上提供了多线程的支持.Java的线程机制是抢占式的.这表示调度机制会周期的中断线程,将上下文切换到另一个线程,从而为每个线程都提供时间片.(与抢占式多线程对应的是 协作式多线 ...

  7. java:多线程基础之Runnable、Callable与Thread

    java.lang包下有二个非常有用的东西:Runnable接口与Thread类,Thread实现了Runnable接口(可以认为Thread是Runnable的子类),利用它们可以实现最基本的多线程 ...

  8. java 多线程实现四种方式解析Thread,Runnable,Callable,ServiceExcutor,Synchronized ,ReentrantLock

    1.Thread实现: import java.util.Date; import java.text.SimpleDateFormat; public class MyThread extends ...

  9. Java 中的“implements Runnable” 和“extends Thread”(转)

    知识点 “implements Runnable” 和“extends Thread”的不同 具体分析 最近在学习Android中的Handler消息传递机制时,创建新线程有两种方式:一种是实现Run ...

随机推荐

  1. [Apache Pulsar] 企业级分布式消息系统-Pulsar快速上手

    Pulsar快速上手 前言 如果你还不了解Pulsar消息系统,可以先看上一篇文章 企业级分布式消息系统-Pulsar入门基础 Pulsar客户端支持多个语言,包括Java,Go,Pytho和C++, ...

  2. IBM实习工作(二)

    2019年秋招前夕再次到ibm项目组参加实习两周,这次主要负责的需求是建立牛奶数据池,在二级菜单建立对账单数据池,数据由Excel导入生成. 分析整个需求,主要分为以下几块: 1.牛奶数据池前台页面, ...

  3. java并发编程(十六)----(线程池)java线程池的使用

    上节我们简单介绍了线程池,这次我们就来使用一下.Executors提供四种线程池,分别是:newCachedThreadPool,newFixedThreadPool ,newScheduledThr ...

  4. java并发编程(十四)----(JUC原子类)对象的属性修改类型介绍

    今天我们介绍原子类的最后一个类型--对象的属性修改类型: AtomicIntegerFieldUpdater,AtomicLongFieldUpdater,AtomicReferenceFieldUp ...

  5. 【0731 | Day 5】Python基础(三)

    Part 10 格式化输出的三种方式 一.占位符 #一般字符串连接/普通形式 ​ name = 'Adela' age = str(22) print('My name is '+ name+ ',' ...

  6. 网络编程网络协议篇(osi七层协议)

    一 互联网的本质 咱们先不说互联网是如何通信的(发送数据,文件等),先用一个经典的例子,给大家说明什么是互联网通信. 现在追溯到八九十年代,当时电话刚刚兴起,还没有手机的概念,只是有线电话,那么此时你 ...

  7. Oracle - SPM固定执行计划(一)

    一.前言 生产中偶尔会碰到一些sql,有多种执行计划,其中部分情况是统计信息过旧造成的,重新收集下统计信息就行了.但是有些时候重新收集统计信息也解决不了问题,而开发又在嗷嗷叫,没时间让你去慢慢分析原因 ...

  8. DFS-深度优先算法解决迷宫问题

    /*main.cpp*/#define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; int sr, sc ...

  9. 【记忆化搜索】掷骰子 hpuoj

    B. 掷骰子 单点时限: 2.0 sec 内存限制: 512 MB 骰子,中国传统民间娱乐用来投掷的博具,早在战国时期就已经被发明. 现在给你 n 个骰子,求 n 个骰子掷出点数之和为 a 的概率是多 ...

  10. Delegate,Block,Notification, KVC,KVO,Target-Action

    Target-Action: 目标-动作机制,所有的UIControl及子类都是这个机制:原理:在对象产生某个事件的特定时刻,给一个对象发送一个消息:类内部target去执行action方法 Dele ...