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

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线程

原文地址:https://www.cnblogs.com/scuwangjun/p/8830438.html

时间: 2024-12-23 18:40:09

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

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

Java中创建线程主要有三种方式: 一.继承Thread类创建线程类 (1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务.因此把run()方法称为执行体. (2)创建Thread子类的实例,即创建了线程对象. (3)调用线程对象的start()方法来启动该线程. package com.thread; public class FirstThreadTest extends Thread{ int i = 0; //重写run方法,run方法的方

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

Java中创建线程主要有三种方式: 一.继承Thread类创建线程类 (1)定义Thread类的子类.并重写该类的run方法,该run方法的方法体就代表了线程要完毕的任务.因此把run()方法称为运行体. (2)创建Thread子类的实例,即创建了线程对象. (3)调用线程对象的start()方法来启动该线程. package com.thread; public class FirstThreadTest extends Thread{ int i = 0; //重写run方法.run方法的方

Java创建线程的三种方式

1.继承Runnable接口 package test; class RunnableDemo implements Runnable{ private Thread t; private String threadName; RunnableDemo(String name){ threadName=name; System.out.println("Creating "+name); } public void run(){ System.out.println("Run

java多线程开启的三种方式

1.继承Thread类,新建一个当前类对象,并且运行其start()方法 1 package com.xiaostudy.thread; 2 3 /** 4 * @desc 第一种开启线程的方式 5 * @author xiaostudy 6 * 7 */ 8 public class Demo1_Thread extends Thread { 9 10 public void run() { 11 for (int i = 0; i < 10; i++) { 12 System.out.pri

创建线程的三种方式

创建线程的三种方式 第一种:通过NSThread的对象方法 第二种:通过NSThread的类方法 第三种:通过NSObject的方法 准备在后台线程调用的方法 longOperation: - (void)longOperation:(id)obj { NSLog(@"%@ - %@", [NSThread currentThread], obj); } 方式1:alloc / init - start - (void)threadDemo1 { NSLog(@"before

Java开启线程的两种方式

------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.ios培训..Net培训</a>.期待与您交流!------ Java开启线程的两种方式: 方式一:成为线程(Thread)的儿子,即继承Thread类简单代码如下:class Student extends Thread{Student(String name){super(name);}public

并发编程(壹):创建线程的三种方式及其对比

创建线程的三种方式及其对比 1. 继承 Thread类 (1). 继承Thread类.并重写run()方法,该方法无参数,无返回值: (2). 创建子类实例,并实例化对象: (3). 通过start()方法启动,注意:不是通过run()方法启动. public class ThreadDemo extends Thread{ public void run(){ System.out.println("继承Thread创建线程的."); } } public class ThreadA

关于PHP、JAVA、.NET这三种技术的区别

关于PHP.JAVA..NET这三种技术的区别 一.语言: PHP:PHP产生与1994年,其语法混合了C.Java.Perl 和他自创的一些编程语法:PHP是嵌入在HTML中执行的:它也是一种解释性语言.早期的PHP并非完全的面向对象编程语言,到了PHP4以后的版本才开始有了面向对象的概念. JAVA:JAVA产生与1995年,JAVA语言和JAVA平台统称为JAVA:它语法与C语言和C++语言很接近,并且JAVA是面向对象编程语言,JAVA是编译性语言,可以先将JAVA源码编译成.class

虚拟机NetworkAdapter三种方式的区别

虚拟机在安装时默认的有三块网卡,VMnet1和VMnet8,另外还有VMnet0 Vmware 还提供了三种网络连接模式: 分别为: A 桥接bridge  B NAT 网络地址转换 C  主机模式 下面来简单说一下 三种方式的区别  : 1) bridge : 默认使用VMnet0,不提供DHCP服务 在桥接模式下,虚拟机和宿主计算机处于同等地位,虚拟机就像是一台真实主机一样存在于局域网中.因此在桥接模式下,我们就要像对待其他真实计算机一样为其配置IP.网关.子网掩码等等.当我们可以自由分配局