Java创建线程的四种方式

1.线程是什么?

线程,有时被称为轻量进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。就绪状态是指线程具备运行的所有条件,逻辑上可以运行,在等待处理机;运行状态是指线程占有处理机正在运行;阻塞状态是指线程在等待一个事件(如某个信号量),逻辑上不可执行。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。

2.线程创建的四种方式

  1. 继承Thread类创建线程,重写run方法
    通过观察Thread类源码,发现Thread实际上是实现了Runnable接口的一个实例,即代表一个线程的实例。
class Thread implements Runnable 

启动线程:调用start()方法即可

start()方法与run()的区别在于:start()(开辟一个新的线程)运行在子线程中;run()运行在原线程;

案例:

class MyThread extends Thread {
    @Override
    public void run() {
        super.run();
        System.out.println("开启线程方式一");
    }
}

使用:

 MyThread thread1 = new MyThread();
        thread1.start();
  1. 实现Runnable接口,重写run方法。通过 public Thread(Runnable target)构造方法创建线程
    当传入一个Runnable target参数给Thread后,Thread的run()方法就会调用target.run(),参考JDK源代码:
/**
     * If this thread was constructed using a separate
     * <code>Runnable</code> run object, then that
     * <code>Runnable</code> object's <code>run</code> method is called;
     * otherwise, this method does nothing and returns.
     * <p>
     * Subclasses of <code>Thread</code> should override this method.
     *
     * @see     #start()
     * @see     #stop()
     * @see     #Thread(ThreadGroup, Runnable, String)
     */
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

案例:

class MyThread2 extends Student implements Runnable {

    @Override
    public void run() {
        System.out.println("开启线程方式二");
    }
}

使用:

  MyThread2 thread2 = new MyThread2();
        Thread thread = new Thread(thread2);
        thread.start();
  1. 实现Callable接口通过FutureTask包装器实现创建线程
    此方法的一般步骤为:
  • 自定义类实现Callable< Object>接口,实现call()方法
  • 实例化自定义类
  • 使用此实例创建FutureTask包装器
  • 通过该包装器实例创建线程

案例:

class ThreadCallable<Object> extends Student implements Callable<Object>{

    @Override
    public Object call() throws Exception {
        System.out.println("实现Callable接口通过FutureTask包装器实现的线程");
        return null;
    }
}

使用:

 //方式三
        //1.创建实现Callable<V>接口的类
        //2.实例化此类对象
        //3.通过该callable实例化FutureTask包装器
        //4.通过该包装器的实例创建线程
        Callable<Object> callable = new ThreadCallable<>();
        FutureTask<Object> futureTask = new FutureTask<>(callable);
        Thread thread3 = new Thread(futureTask);
        thread3.start();
  1. 通过线程池创建线程
  • 通过Executors的静态方法创建线程池
  • 通过线程池执行submit等方法即可获取Future对象,通过它.get()方法即获取返回值;get为线程阻塞
    案例:
package com.wdl.kt.java.thread;

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

/**
 * @program: kt1
 * @description: 开启线程的四种方式
 * @author: wdl
 * @create: 2018-11-23 20:46

*/

public class Main {
    public static void main(String[] args) {
//        //方式1
//        MyThread thread1 = new MyThread();
//        thread1.start();
//
//        //方式2
//        MyThread2 thread2 = new MyThread2();
//        Thread thread = new Thread(thread2);
//        thread.start();

        //方式三
        //1.创建实现Callable<V>接口的类
        //2.实例化此类对象
        //3.通过该callable实例化FutureTask包装器
        //4.通过该包装器的实例创建线程
//        Callable<Object> callable = new ThreadCallable<>();
//        FutureTask<Object> futureTask = new FutureTask<>(callable);
//        Thread thread3 = new Thread(futureTask);
//        thread3.start();


        //方式4
        //通过线程池
        //1.创建一个固定大小的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        List<Future> arrayList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            //RunnableThread runnableThread = new RunnableThread();
            //executorService.execute(runnableThread);
            //executorService.submit(runnableThread);
            Callable<String> callable = new ThreadCallable<>(""+i);
            Future future = executorService.submit(callable);
            arrayList.add(future);
        }
        for (Future future : arrayList) {
            try {
                System.out.println(future.get().toString());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        executorService.shutdown();
    }
}

class Student {
}

//class MyThread extends Thread {
//    @Override
//    public void run() {
//        super.run();
//        System.out.println("开启线程方式一");
//    }
//}

//class MyThread2 extends Student implements Runnable {
//
//
//    @Override
//    public void run() {
//        System.out.println("开启线程方式二");
//    }
//}

class ThreadCallable<Object> extends Student implements Callable<Object>{

    private String taskNumber;

    public ThreadCallable(String taskNumber) {
        this.taskNumber = taskNumber;
    }
    @Override
    public Object call() throws Exception {
        Date date = new Date();
        long x = date.getTime();
        Thread.sleep(1000);
        Date date1 = new Date();
        long y = date1.getTime();
        //System.out.println("实现Callable接口通过FutureTask包装器实现的线程");
        String s = taskNumber+" 运行时间为:"+(y-x);
        return (Object) s;
    }
}


//class RunnableThread implements Runnable{
//    @Override
//    public void run() {
//        System.out.println("通过线程池创建的线程:"+Thread.currentThread().getName()+" ");
//    }
//}

其中ExecutorService提供了submit方法,传递一个Callable或者Runnable,获取一个Future对象。如果Executor后台线程池还没有完成Callable的计算,调用返回Future对象的get()方法,会阻塞直到计算完成。

以上就是创建线程的四种方法。

3.上述四种方式可大体分为2类:

  1. 前两种:返回值的线程
  2. 后两种:返回值的线程
  3. 其中Callable与Runnable两个接口的区别:

①Callable下的方法是call(),Runnable下的方法是run()①Callable下的方法是call(),Runnable下的方法是run()
②Callable可得到返回值,可抛出异常;Runnable都不可以
③运行Callable任务可得到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成以及检索计算结果;通过Future对象可以了解任务执行的情况,取消任务的执行,获取任务执行的结果
④Thread只支持Runnable接口不支持Callable接口–因此才引入FutureTask

Future接口:

public interface Future<V> {

    boolean cancel(boolean mayInterruptIfRunning);

    boolean isCancelled();

    boolean isDone();

    V get() throws InterruptedException, ExecutionException;

    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

4.其中Executors类提供了以下静态方法用来创建线程池,返回的线程池都实现了ExecutorService接口:

  1. public static ExecutorService newFixedThreadPool(int nThreads)创建固定数目的线程池
  2. public static ExecutorService newCachedThreadPool() 创建一个可缓存的线程池,调用execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
  3. public static ExecutorService newSingleThreadExecutor()创建一个单线程的线程池。
  4. public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)创建一个可执行周期性动作或者定时任务的线程池。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值