面试系列之-线程创建方法(JAVA基础)

2023-08-21 20:19:09 浏览数 (1)

  1. 继承Thread类创建线程类

(1)需要继承Thread类,创建一个新的线程类;

(2)同时重写run()方法,将需要并发执行的业务代码编写在run()方法中;

代码语言:javascript复制
public class CreateDemo {
    public static final int MAX_TURN = 5;
    public static String getCurThreadName() {
        return Thread.currentThread().getName();
    }
    //线程的编号
    static int threadNo = 1;
    static class DemoThread extends Thread { //①
        public DemoThread() {
            super("DemoThread-"   threadNo  ); //②
        }
        public void run() { //③
            for (int i = 1; i < MAX_TURN; i  ) {
                Print.cfo(getName()   ", 轮次:"   i);
            }
            Print.cfo(getName()   " 运行结束.");
        }
    }
    public static void main(String args[]) throws InterruptedException {
        Thread thread = null;
        //方法一:使用Thread子类创建和启动线程
        for (int i = 0; i < 2; i  ) {
            thread = new DemoThread();
            thread.start();
        }
        Print.cfo(getCurThreadName()   " 运行结束.");
    }
}
  1. 实现Runnable接口创建线程目标类

2.1 通过匿名类创建Runnable线程目标类

代码语言:javascript复制
public class CreateDemo2 {
    public static final int MAX_TURN = 5;
    static int threadNo = 1;
    public static void main(String args[]) throws InterruptedException {
        Thread thread = null;
        //使用Runnable的匿名类创建和启动线程
        for (int i = 0; i < 2; i  ) {
            thread = new Thread(new Runnable() { //① 匿名实例
                @Override
                public void run() { //② 异步执行的业务逻辑
                    for (int j = 1; j < MAX_TURN; j  ) {
                        Print.cfo(getCurThreadName()   ", 轮次:"   j);
                    }
                    Print.cfo(getCurThreadName()   " 运行结束.");
                }
            }, "RunnableThread"   threadNo  );
            thread.start();
        }
        Print.cfo(getCurThreadName()   " 运行结束.");
    }
}

2.2 实现Runnable接口的方式创建线程目标类

代码语言:javascript复制
package com.crazymakercircle.multithread.basic.create;
// 省略import
public class SalesDemo{
    public static final int MAX_AMOUNT = 5; //商品数量
    //商店商品类(销售线程类),一个商品一个销售线程,每个线程异步销售4次
    static class StoreGoods extends Thread{
        StoreGoods(String name){
            super(name);
        }
        private int goodsAmount = MAX_AMOUNT;
        public void run(){
            for (int i = 0; i <= MAX_AMOUNT; i  ){
                if (this.goodsAmount > 0){
                    Print.cfo(getCurThreadName()   " 卖出一件,还剩:"
                                (--goodsAmount));
                    sleepMilliSeconds(10);
                }
            }
            Print.cfo(getCurThreadName()   " 运行结束.");
        }
    }
    //商场商品类(target销售线程的目标类),一个商品最多销售4次,可以多人销售
    static class MallGoods implements Runnable{
        //多人销售可能导致数据出错,使用原子数据类型保障数据安全
        private AtomicInteger goodsAmount = new AtomicInteger(MAX_AMOUNT);
        public void run(){
            for (int i = 0; i <= MAX_AMOUNT; i  ){
                if (this.goodsAmount.get() > 0){
                    Print.cfo(getCurThreadName()   " 卖出一件,还剩:"
                                (goodsAmount.decrementAndGet()));
                    sleepMilliSeconds(10);
                }
            }
            Print.cfo(getCurThreadName()   " 运行结束.");
        }
    }
    public static void main(String args[]) throws InterruptedException{
        Print.hint("商店版本的销售");
        for (int i = 1; i <= 2; i  ){
            Thread thread = null;
            thread = new StoreGoods("店员-"   i);
            thread.start();
        }
        Thread.sleep(1000);
        Print.hint("商场版本的销售");
        MallGoods mallGoods = new MallGoods();
        for (int i = 1; i <= 2; i  ){
            Thread thread = null;
            thread = new Thread(mallGoods, "商场销售员-"   i);
            thread.start();
        }
        Print.cfo(getCurThreadName()   " 运行结束.");
    }
}
  1. 使用Callable和FutureTask创建线程

对Future接口的主要方法详细说明如下:

·V get():获取异步任务执行的结果。注意,这个方法的调用是阻塞性的。如果异步任务没有执行完成,异步结果获取线程(调用线程)会一直被阻塞,一直阻塞到异步任务执行完成,其异步结果返回给调用线程。

·V get(Long timeout,TimeUnit unit):设置时限,(调用线程)阻塞性地获取异步任务执行的结果。该方法的调用也是阻塞性的,但是结果获取线程(调用线程)会有一个阻塞时长限制,不会无限制地阻塞和等待,如果其阻塞时间超过设定的timeout时间,该方法将抛出异常,调用线程可捕获此异常。

·boolean isDone():获取异步任务的执行状态。如果任务执行结束,就返回true。

·boolean isCancelled():获取异步任务的取消状态。如果任务完成前被取消,就返回true。

·boolean cancel(boolean mayInterruptRunning):取消异步任务的执行。

FutureTask类和Callable接口的联合使用可以创建能够获取异步执行结果的线程:

(1)创建一个Callable接口的实现类,并实现其call()方法,编写好异步执行的具体逻辑,可以有返回值。

(2)使用Callable实现类的实例构造一个FutureTask实例。

(3)使用FutureTask实例作为Thread构造器的target入参,构造新的Thread线程实例。

(4)调用Thread实例的start()方法启动新线程,启动新线程的run()方法并发执行。其内部的执行过程为:启动Thread实例的run()方法并发执行后,会执行FutureTask实例的run()方法,最终会并发执行Callable实现类的call()方法。

(5)调用FutureTask对象的get()方法阻塞性地获得并发线程的执行结果。

代码语言:javascript复制
public class CreateDemo3 {
    public static final int MAX_TURN = 5;
    public static final int COMPUTE_TIMES = 100000000;
    //①创建一个 Callable 接口的实现类
    static class ReturnableTask implements Callable<Long> {
        //②编写好异步执行的具体逻辑,可以有返回值
        public Long call() throws Exception{
            long startTime = System.currentTimeMillis();
            Print.cfo(getCurThreadName()   " 线程运行开始.");
            Thread.sleep(1000);
            for (int i = 0; i < COMPUTE_TIMES; i  ) {
                int j = i * 10000;
            }
            long used = System.currentTimeMillis() - startTime;
            Print.cfo(getCurThreadName()   " 线程运行结束.");
            return used;
        }
    }
    public static void main(String args[]) throws InterruptedException {
        ReturnableTask task=new ReturnableTask();//③
        FutureTask<Long> futureTask = new FutureTask<Long>(task);//④
        Thread thread = new Thread(futureTask, "returnableThread");//⑤
        thread.start();//⑥
        Thread.sleep(500);
        Print.cfo(getCurThreadName()   " 让子弹飞一会儿.");
        Print.cfo(getCurThreadName()   " 做一点自己的事情.");
        for (int i = 0; i < COMPUTE_TIMES / 2; i  ) {
            int j = i * 10000;
        }
        Print.cfo(getCurThreadName()   " 获取并发任务的执行结果.");
        try {
            Print.cfo(thread.getName() "线程占用时间:"
                        futureTask.get());//⑦
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        Print.cfo(getCurThreadName()   " 运行结束.");
    }
}
  1. 通过线程池创建线程
代码语言:javascript复制
public class CreateDemo4{
    public static final int MAX_TURN = 5;
    public static final int COMPUTE_TIMES = 100000000;
    //创建一个包含三个线程的线程池
    private static ExecutorService pool = Executors.newFixedThreadPool(3);
    static class DemoThread implements Runnable{
        @Override
        public void run(){
            for (int j = 1; j < MAX_TURN; j  ){
                Print.cfo(getCurThreadName()   ", 轮次:"   j);
                sleepMilliSeconds(10);
            }
        }
    }
    static class ReturnableTask implements Callable<Long>{
        //返回并发执行的时间
        public Long call() throws Exception{
            long startTime = System.currentTimeMillis();
            Print.cfo(getCurThreadName()   " 线程运行开始.");
            for (int j = 1; j < MAX_TURN; j  ){
                Print.cfo(getCurThreadName()   ", 轮次:"   j);
                sleepMilliSeconds(10);
            }
            long used = System.currentTimeMillis() - startTime;
            Print.cfo(getCurThreadName()   " 线程运行结束.");
            return used;
        }
    }
    public static void main(String[] args) {
        pool.execute(new DemoThread()); //执行线程实例,无返回
        pool.execute(new Runnable(){
          @Override
          public void run(){
            for (int j = 1; j < MAX_TURN; j  ){
              Print.cfo(getCurThreadName()   ", 轮次:"   j);
              sleepMilliSeconds(10);
            }
          }
      });
        //提交Callable 执行目标实例,有返回
        Future future = pool.submit(new ReturnableTask());
        Long result = (Long) future.get();
        Print.cfo("异步任务的执行结果为:"   result);
        sleepSeconds(Integer.MAX_VALUE);
    }
}

0 人点赞