Java实现线程的三种方式和区别

Java实现线程的三种方式:

  1. 继承Thread
  2. 实现Runnable接口
  3. 实现Callable接口

区别:

  1. 第一种方式继承Thread就不能继承其他类了,后面两种可以;
  2. 使用后两种方式可以多个线程共享一个target;
  3. Callable比Runnable多一个返回值,并且call()方法可以抛出异常;
  4. 访问线程名,第一种直接使用this.getName(),后两种使用Thread.currentThread().getName()。

下面我们通过代码来看一下实现和区别:

三种实现:

//1. 继承Thread,重写run()方法
class Thread1 extends Thread { private int n = 5; @Override
public void run() {
while(n > 0) {
System.out.println("name:" + this.getName() + ", n:" + n);
n--;
}
}
}
//2. 实现Runnable接口,实现run()方法
class Thread2 implements Runnable { private int n = 5; @Override
public void run() {
while(n > 0) {
System.out.println("name:" + Thread.currentThread().getName() + ", n:" + n);
n--;
}
}
}
//3. 实现Callable接口,实现call()方法,带有返回值和异常
class Thread3 implements Callable<String> { private int n = 5; @Override
public String call() throws Exception {
while(n > 0) {
System.out.println("name:" + Thread.currentThread().getName() + ", n:" + n);
n--;
}
return String.valueOf(n);
} }

如何使用:

//第一种实现方式
Thread1 t11 = new Thread1();
Thread1 t12 = new Thread1();
Thread1 t13 = new Thread1(); t11.start();
t12.start();
t13.start(); //第二种实现方式
Thread2 t21 = new Thread2();
Thread2 t22 = new Thread2();
Thread2 t23 = new Thread2(); Thread t211 = new Thread(t21);
Thread t212 = new Thread(t22);
Thread t213 = new Thread(t23); t211.start();
t212.start();
t213.start(); //第三种实现
Thread3 t31 = new Thread3();
Thread3 t32 = new Thread3();
Thread3 t33 = new Thread3(); FutureTask<String> f1 = new FutureTask<>(t31);
FutureTask<String> f2 = new FutureTask<>(t32);
FutureTask<String> f3 = new FutureTask<>(t33); Thread t311 = new Thread(f1);
Thread t312 = new Thread(f2);
Thread t313 = new Thread(f3); t311.start();
t312.start();
t313.start();

从代码可以看出以上提到的区别1,3,4。那么区别2共享一个target是什么意思呢?

首先我们看一下上述代码的运行结果,

第一种:

name:Thread-1, n:5
name:Thread-1, n:4
name:Thread-1, n:3
name:Thread-1, n:2
name:Thread-1, n:1
name:Thread-2, n:5
name:Thread-2, n:4
name:Thread-2, n:3
name:Thread-2, n:2
name:Thread-2, n:1
name:Thread-0, n:5
name:Thread-0, n:4
name:Thread-0, n:3
name:Thread-0, n:2
name:Thread-0, n:1

第二种:

name:Thread-4, n:5
name:Thread-4, n:4
name:Thread-4, n:3
name:Thread-3, n:5
name:Thread-5, n:5
name:Thread-3, n:4
name:Thread-4, n:2
name:Thread-4, n:1
name:Thread-3, n:3
name:Thread-3, n:2
name:Thread-3, n:1
name:Thread-5, n:4
name:Thread-5, n:3
name:Thread-5, n:2
name:Thread-5, n:1

可以看到,这两种方式的结果一样,都是new了三个线程,每个线程内部循环5次。d第二种方式并没有体现共用同一个target。如果我们将第二种创建线程的方式改为:

//第二种实现方式
Thread2 t21 = new Thread2();
Thread2 t22 = new Thread2();
Thread2 t23 = new Thread2(); Thread t211 = new Thread(t21);
Thread t212 = new Thread(t21);
Thread t213 = new Thread(t21); t211.start();
t212.start();
t213.start();

看一下运行结果:

name:Thread-4, n:5
name:Thread-4, n:4
name:Thread-4, n:3
name:Thread-4, n:2
name:Thread-4, n:1
name:Thread-3, n:5
name:Thread-5, n:5

可以看到,虽然也启动了3个线程,但是由于共享一个target,n的值改变了,其他两个线程也会知道,所以因此一共循环了5次。但是这里明明是7次啊,这是由于多线程的同步问题,可以给run方法加上synchronized关键字解决:

@Override
public synchronized void run() {
while(n > 0) {
System.out.println("name:" + Thread.currentThread().getName() + ", n:" + n);
n--;
}
}

运行结果:

name:Thread-3, n:5
name:Thread-3, n:4
name:Thread-3, n:3
name:Thread-3, n:2
name:Thread-3, n:1

这里可能有点迷惑,只启动了一个线程啊。其实另外两个线程也启动了,只是这个时候n=0无法进入循环。我们可以加一行打印:

@Override
public synchronized void run() {
System.out.println("进入" + Thread.currentThread().getName() + "线程");
while(n > 0) {
System.out.println("name:" + Thread.currentThread().getName() + ", n:" + n);
n--;
}
}

可以看到运行结果:

进入Thread-3线程
name:Thread-3, n:5
name:Thread-3, n:4
name:Thread-3, n:3
name:Thread-3, n:2
name:Thread-3, n:1
进入Thread-5线程
进入Thread-4线程

Java实现线程的三种方式和区别的更多相关文章

  1. Java并发编程:Java创建线程的三种方式

    目录 引言 创建线程的三种方式 一.继承Thread类 二.实现Runnable接口 三.使用Callable和Future创建线程 三种方式的对比 引言 在日常开发工作中,多线程开发可以说是必备技能 ...

  2. java创建线程的三种方式及其对比

    第一种方法:继承Thread类,重写run()方法,run()方法代表线程要执行的任务.第二种方法:实现Runnable接口,重写run()方法,run()方法代表线程要执行的任务.第三种方法:实现c ...

  3. AJPFX总结java创建线程的三种方式及其对比

    Java中创建线程主要有三种方式: 一.继承Thread类创建线程类 (1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务.因此把run()方法称为执行 ...

  4. java创建线程的三种方式及其对照

    Java中创建线程主要有三种方式: 一.继承Thread类创建线程类 (1)定义Thread类的子类.并重写该类的run方法,该run方法的方法体就代表了线程要完毕的任务.因此把run()方法称为运行 ...

  5. Java中创建线程的三种方式以及区别

    在java中如果要创建线程的话,一般有3种方法: 继承Thread类: 实现Runnable接口: 使用Callable和Future创建线程. 1. 继承Thread类 继承Thread类的话,必须 ...

  6. Java创建线程的三种方式

    一.继承Thread类创建线程类 (1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务.因此把run()方法称为执行体. (2)创建Thread子类的实 ...

  7. Java创建线程的三种形式的区别以及优缺点

    1.实现Runnable,Callable Callable接口里定义的方法有返回值,可以声明抛出异常. 继承Callable接口实现线程 class ThreadCall implements Ca ...

  8. Java终止线程的三种方式

    停止一个线程通常意味着在线程处理任务完成之前停掉正在做的操作,也就是放弃当前的操作. 在 Java 中有以下 3 种方法可以终止正在运行的线程: 使用退出标志,使线程正常退出,也就是当 run() 方 ...

  9. 0036 Java学习笔记-多线程-创建线程的三种方式

    创建线程 创建线程的三种方式: 继承java.lang.Thread 实现java.lang.Runnable接口 实现java.util.concurrent.Callable接口 所有的线程对象都 ...

随机推荐

  1. PHP函数问题

    有时候,运行nginx和PHP CGI(PHP FPM)web服务的Linux服务器,突然系统负载上升,用top命令查看,很多phpcgi进程的CPU利用率接近100%后来通过跟踪发现,这种情况与PH ...

  2. 什么是DDOS

    什么是DDOS?分布式拒绝服务攻击(Distributed Denial of Service).百度的解释有一个形象的例子我认为比较好理解,照搬如下:   一群恶霸试图让对面那家有着竞争关系的商铺无 ...

  3. Xmind ZEN破解版来袭:如何去除水印

    Xmind ZEN是一款十分优雅地思维导图软件,但是找不到其破解版,在导出图片时就会携带上水印. image-20190110110013642.png 当然,土豪请(点击这里关闭). image-2 ...

  4. 作为一个java高级工程师的进阶之路

    本文可能可能更偏向于是内心的独白篇和面试技巧总结 一.独白 之前也面试别人,现在轮到自己找工作,怎么说呢,每个面试官的看法不一样,面试的方式就不一样,比如我面试别人我喜欢问项目中他用到了那些,然后针对 ...

  5. 【OGG 故障处理】OGG-01031

    故障原因 -------------------- 网络异常,导致DP进程异常中断   故障现象 -------------------- 源端DP 进程全部挂起,且启动失败 GGSCI 34> ...

  6. smart_ptr之shared_ptr

    智能指针的概念 c++11标准和boost都提供了智能指针的功能.智能指针是普通指针的封装,智能指针是一个对象,对象里面包含了原生指针.可以使用智能指针对象的get()方法可获得封装在里面的原生指针. ...

  7. MySQL菜鸟入门“秘籍”

    一.MySQL简介 1.什么是数据库 ? 数据库(Database)是按照数据结构来组织.存储和管理数据的仓库,它产生于距今六十多年前,随着信息技术和市场的发展,特别是二十世纪九十年代以后,数据管理不 ...

  8. 02.python网络爬虫第二弹(http和https协议)

    一.HTTP协议 1.官方概念: HTTP协议是 Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(www.world wide web) 服务器传输超 ...

  9. 【转】解决高版本springboot对Velocity不支持

    https://blog.csdn.net/sinat_31270499/article/details/82283880 最近在做关于Spring Boot开发的项目,因为项目中要用到Velocit ...

  10. Java&Selenium数据驱动【DataProvider+TestNG+Array】

    Java&Selenium数据驱动[DataProvider+TestNG+Array] package testNGWithDataDriven; import java.util.conc ...