java多线程创建-Thread,Runnable,callable和threadpool

java创建多线程的方式有许多种,这里简要做个梳理

1. 继承Thread类
继承java.lang.Thread类,创建本地多线程的类,重载run()方法,调用Thread的方法启动线程。示例代码如下:

MyThread.java

public class MyThread extends Thread {

    public void run(){
        private int copy = 0;
        System.out.println("Thread id:" + Thread.currentThread().getName()+" == print time:" + System.currentTimeMillis());
        System.out.println("Thread serialnum:" + ++copy);
        try {

            sleep(1000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        System.out.println("Thread id:" + Thread.currentThread().getName()+" == print time:" + System.currentTimeMillis());

    }

    public static void main(String[] args){

        MyThread mt1 = new MyThread();

        MyThread mt2 = new MyThread();

        MyThread mt3 = new MyThread();

        System.out.println("Start all Threads:");

        mt1.start();

        mt2.start();

        mt3.start();
    }
}

输出结果:

Start all Threads:
Thread id:Thread-0 == print time:1495975884383
Thread serialnum:1
Thread id:Thread-1 == print time:1495975884383
Thread serialnum:1
Thread id:Thread-2 == print time:1495975884383
Thread serialnum:1
Thread id:Thread-1 == print time:1495975885385
Thread id:Thread-0 == print time:1495975885385
Thread id:Thread-2 == print time:1495975885385

2. 实现Runnable接口

实现java.lang.Runnable接口的run方法,使用实现的对象实例化Thread类,调用Thread对象的start()方法。
示例代码:

public class MyRunnable implements Runnable {

    private int copy = 0;

    public void run(){
        System.out.println("Thread id:" + Thread.currentThread().getName()+" == print time:" + System.currentTimeMillis());
        System.out.println("Thread serialnum:" + ++copy);
        try {
            sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Thread id:" + Thread.currentThread().getName()+" == print time:" + System.currentTimeMillis());
    }

    public static void main(String[] args){
        MyRunnable mr = new MyRunnable();
        System.out.println("Start all Threads:");
        new Thread(mr).start();
        new Thread(mr).start();
        new Thread(mr).start();
    }
}

输出结果:

Start all Threads:
Thread id:Thread-0 == print time:1495975833588
Thread id:Thread-1 == print time:1495975833588
Thread serial:1
Thread id:Thread-2 == print time:1495975833588
Thread serial:2
Thread serial:3
Thread id:Thread-0 == print time:1495975834603
Thread id:Thread-1 == print time:1495975834603
Thread id:Thread-2 == print time:1495975834603

对比Thread方法和Runnable方法的使输出结果不难发现:
. 二者均可实现多线程并发效果
. Runnable的方法可以使用一个Runnable对象创建多个线程,这多个线程共享其依赖的Runnable对象的资源,适用于多个线程处理相同资源的场景(网上举得较多的例子:卖票);Thread的方法则是完全相互独立的线程

事实上,嫌贵而言,当前Runnable使用的要比Thread方法普遍的多,除了上面说的资源共享的原因之外,Java的单继承特性也增大了Thread方法的局限性。

3. 实现Callable接口
相对于上述继承Thread类的方法和实现Runnable接口的方法,实现Callable接口的方法不但可以可以实现多线程并发,还能够处理线程的返回值或者获取执行异常。使用Callable实现多线程编程需要实现Callable的call方法(在call方法中指定返回值,抛出异常),构造与之关联的FutureTask对象,启动线程后,线程执行的结果会存储在FutureTask对象中,可以使用FutureTask的get方法获取。示例代码:

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import static java.lang.Thread.sleep;

public class MyCallable implements Callable<Integer> {
    private int flag = 0;

    public Integer call() throws Exception {
        System.out.println("Thread id:" + Thread.currentThread().getName() + "  == print time:"+System.currentTimeMillis());
        sleep(10000);
        System.out.println("Thread id:" + Thread.currentThread().getName() + "  == print time:"+System.currentTimeMillis());
        ++flag;
        return flag;
    }

    public static void main(String[] args) throws Exception{
        MyCallable myCallable = new MyCallable();
        FutureTask<Integer> future = new FutureTask<Integer>(myCallable);
        FutureTask<Integer> future2 = new FutureTask<Integer>(myCallable);
        new Thread(future).start();
        new Thread(future2).start();
        int Result,Result2;
//        while (!future.isDone());
        Result = future.get();
//
//        while(!future2.isDone());
        Result2 = future2.get();

        System.out.println("GET THREAD NAME:"+ Result );
        System.out.println("GET THREAD NAME 2:"+Result2);
    }
}

执行结果:

Thread id:Thread-0  == print time:1495997744617
Thread id:Thread-1  == print time:1495997744617
Thread id:Thread-0  == print time:1495997754625
Thread id:Thread-1  == print time:1495997754625
GET THREAD NAME:1
GET THREAD NAME 2:2

上述代码执行逻辑与前面Runnale的示例代码类似,通过构造Thread对象来启动多线程。区别在于此处构造了futureTask方法用来用来存储线程返回值。需要注意的是,线程的Callable泛型接口里的类型和call()方法的返回值类型和FutureTask的泛型接口类型要一致。

4. 使用线程池和Executor框架
前面的三种方案,我们创建了Runnable或者Callable或者Thread的任务,扔到Thread中去启动,我们需要手动去管理各种多线程的参数,比如线程数量,线程复用,线程安全的控制等。Java5以后的版本提供了Executor技术,能够提供搭建好的线程池,为多线程提供了完整的解决方案,能够有效的管理线程数量,线程复用策略,保证线程安全,避免this逃逸问题等。
Executor提供的线程池方案包括newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool和SingleThreadExecutor(Fork/Join框架还提供了一个newWorkStealingPool),这些线程池分别提供了不同的线程管理方案,执行返回一个ExecutorService对象,这个对象可以调用execute()方法或者submit()方法,将前面定义的Runnable任务或者Callable任务或者Thread任务提交到各个线程去执行

我们以比较常用的newCachedThreadPool()为例,下面示例代码使用ExecutorService执行一个Callable对象任务,获取每个线程的返回值。

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

import static java.lang.Thread.sleep;

public class MyCallable2 implements Callable<String> {

    public String call() throws Exception{
        sleep(1000);
        System.out.println("terminate the thread : "+Thread.currentThread().getName());
        return Thread.currentThread().getName();
    }

    public static void main(String[] args){
        ExecutorService es = Executors.newCachedThreadPool();
        List<Future<String>> futureList = new ArrayList<Future<String>>();
        for(int i=0;i<5;i++){
            Future future = es.submit(new MyCallable2());
            futureList.add(future);
        }

        for (Future f: futureList
             ) {
            while(!f.isDone());
            try {
                System.out.println("EXECUTE RESULT:"+f.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
            finally {
                es.shutdown();
            }
        }
    }
}

执行结果如下:

terminate the thread : pool-1-thread-5
terminate the thread : pool-1-thread-4
terminate the thread : pool-1-thread-3
terminate the thread : pool-1-thread-2
terminate the thread : pool-1-thread-1
EXECUTE RESULT:pool-1-thread-1
EXECUTE RESULT:pool-1-thread-2
EXECUTE RESULT:pool-1-thread-3
EXECUTE RESULT:pool-1-thread-4
EXECUTE RESULT:pool-1-thread-5

使用Executors创建Runnable线程与创建Callable线程的方法类似,且不用管理返回值,相对更加简单,此处不再赘述。

时间: 2024-08-01 12:42:31

java多线程创建-Thread,Runnable,callable和threadpool的相关文章

Java多线程中的Runnable和Thread

摘要: 在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口:Thread类是在java.lang包中定义的.一个类只要继承了Thread类同时覆写了本类中的run()方法就可以实现多线程操作了,但是一个类只能继承一个父类,这是此方法的局限. 用法: Thread: package org.thread.demo;class MyThread extends Thread{ private String name; public MyThread(Stri

java多线程创建方法

1.继承Thread类 2.实现Runnable接口 3.两种实现方法之间的关系 4.实例 sleep是属于Thread类的静态函数. /** * aThread.java * @author cjc */ public class aThread extends Thread { public void run() { for(int i=0;i<10;i++) { System.out.println("The son thread1 is running..."); try

java 线程 --- Thread,Runnable,Callable 基础学习

java 使用 Thread 类代表线程,所有现场对象都必须是 Thread 类或者其子类的实例.每个线程的作用是完成一定的任务,实际上就是执行一段程序流.java 使用线程执行体来代表这段程序流. 1.继承Thread 类创建线程 启动多线程的步骤如下: (1)定义Thread 类的子类,并重写该类的run() 方法,该run() 方法的方法体就代表类线程需要完成的任务.因此把run() 方法称为线程执行体. (2)创建 Thread 子类的实例,即创建线程对象. (3)调用线程的star()

Java多线程01(Thread类、线程创建、线程池)

Java多线程(Thread类.线程创建.线程池) 第一章 多线程 1.1 多线程介绍 1.1.1 基本概念 进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程.一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序. 简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程 1.1.2 单线程程序 - 从入口m

Java 多线程(1)-Thread和Runnable

一提到Java多线程,首先想到的是Thread继承和Runnable的接口实现 Thread继承 public class MyThread extends Thread { public void run(){ int i = 0; System.out.println("--------------"+i++); } } Runnable接口实现 public class RunnableImpl implements Runnable { private long value =

Java多线程extends Thread和implements Runnable

大家都知道,要实现Java多线程的两种方式 a:是直接继承Thread类,b:是实现Runnable接口. 先上代码: a:是直接继承Thread类, public class ThreadDemo1 extends Thread {    public void run(){        //Thread.currentThread().getName() 和 this.getName()都可以用来获得线程的名称        System.out.println("线程的名称:"

第五周作业(Java多线程创建的三个方法)

我最近在学习Java中多线程,并且觉得多线程这块在以后的Java开发中显得极为重要,就谈一下Java实现多线程的三种方式. JAVA多线程实现方式主要有三种:继承Thread类.实现Runnable接口.使用ExecutorService.Callable.Future实现有返回结果的多线程.其中前两种方式线程执行完后都没有返回值,只有第三种是带返回值的,这种方式一般要求比较高,并且较前两种难一些. 1.继承Thread类实现多线程继承Thread类的本质上也是实现了Runnable接口的一个实

Java多线程——创建线程的两种方式

创建线程方式一:继承Thread类. 步骤:1,定义一个类继承Thread类.2,覆盖Thread类中的run方法.3,直接创建Thread的子类对象创建线程.4,调用start方法开启线程并调用线程的任务run方法执行. 可以通过Thread的getName获取线程的名称 Thread-编号(从0开始)主线程的名字就是main. 例: class Demo extends Thread { private String name; Demo(String name) { super(name)

Java多线程--创建线程

1.创建线程 在Java中创建线程有两种方法:使用Thread类和使用Runnable接口.在使用Runnable接口时需要建立一个Thread实例.因此,无论是通过Thread类还是Runnable接口建立线程,都必须建立Thread类或它的子类的实例.Thread构造函数: public Thread( ); public Thread(Runnable target); public Thread(String name); public Thread(Runnable target, S