二、JUC入门——线程创建(线程池详细说明)

   日期:2020-07-08     浏览:116    评论:0    
核心提示:线程创建线程的几种方式1、继承Thread类2、实现Runnable接口3、实现Callable接口4、线程池三级目录创建线程的几种方式在创建线程之前,我们要先熟悉一个类Thread;public class Thread implements Runnable { private static native void registerNati

线程

  • 创建线程的几种方式
    • 1、继承Thread类
    • 2、实现Runnable接口
    • 3、实现Callable接口
    • 4、线程池
    • 创建线程几种方式
    • 线程池详细解析

创建线程的几种方式

在创建线程之前,我们要先熟悉一个类Thread;

public class Thread implements Runnable {
    
    private static native void registerNatives();
    static {
        registerNatives();
    }
    
       
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }
}

重写的Runnable接口的run方法,为业务运行代码编写的地方,如果我们要实现业务书写,也需要重写run方法,再通过点start方法启动线程,等待CPU调用!

1、继承Thread类


class ExtendsThread extends Thread{
    @Override
    public void run() {
        System.out.println("继承Thread方式创建线程,重写run方法");
    }
      //启动线程方法见下方
}

2、实现Runnable接口


class RunnableImpl implements Runnable{

    @Override
    public void run() {
        System.out.println("实现Runnable接口方式创建线程,重写run方法");
    }
    //启动线程方法见下方
}

3、实现Callable接口



class CallableImp implements Callable<Object>{
	
    @Override
    public Object call() throws Exception {
        System.out.println("实现Callable接口方式创建线程,重写call方法,有返回值");
        return "输出Callable的返回值";
    }
    //可以通过FutureTask类的其中一个构造方法使用Callable,另外一个构造方法可以使用Runnable 
    public static void main(String[] args) throws Exception {
        CallableImp callableImp = new CallableImp();
        FutureTask<Object> objectFutureTask = new FutureTask<>(callableImp);
        Thread thread1 = new Thread(objectFutureTask);
        thread1.start();
        //打印返回值
        System.out.println(objectFutureTask.get());
    }
}

4、线程池

// 第四种,线程池
// 【强制--来自阿里巴巴Java开发手册】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,
// 这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险;
// ExecutorService executorService = Executors.newSingleThreadExecutor();
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5,10,5000, TimeUnit.MICROSECONDS,
                new ArrayBlockingQueue<>(5),new ThreadPoolExecutor.AbortPolicy());
        for (int i = 0; i <10 ; i++) {
         //有返回值方式执行业务业务方法,参考第三种线程创建方式Callable;来自接口ExecutorService的submit(Runnable task)执行
            Future<Object> submit = threadPoolExecutor.submit(new Callable<Object>() {
                @Override
                public Object call() throws Exception {
                    System.out.println("submit运行线程"+Thread.currentThread().getName());
                    return "线程池的submit(Callable)";
                }
            });
            System.out.println("------------------"+submit.get());
            //线程池无返回值方式执行业务方法,调用父类线程池Executor中的execute(Runnable command)实现;(new Runnable为匿名内部类!)
            threadPoolExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("execute运行线程"+Thread.currentThread().getName());
                }
            });
        }

这里重点讲解线程池之前,简单过一下main中,使用线程的几种方式!

创建线程几种方式

 public static void main(String[] args){
// 第一种创建方式:使用继承Thread的对象
        ExtendsThread extendsThread = new ExtendsThread();
        extendsThread.start();
// 第二种创建方式,使用runnable的实现类
        RunnableImpl runnable = new RunnableImpl();
// 创建线程(使用有参构造函数)
        Thread thread = new Thread(runnable);
// 启动线程,但是并不一定启动后立马执行哦
        thread.start();
// 第三种,使用无参构造方法,重写Thread的run方法!:也可以直接使用用匿名内部类方式,具体其他创建方式还可查看Thread的其他构造函数(也可以使用匿名内部类)
        new Thread(){
            @Override
            public void run() {
                //我们的业务方法
            }
        }.start();
        		//匿名内部类(来自new Runnable接口!)
        new Thread(new Runnable() {
            @Override
            public void run() {
			//我们的run里面写的业务代码!
            }
        }).start();
        //lamda表达式,等价于上面那种写法!!
        new Thread(()->{
			//我们的run里面写的业务代码!具体lamda表达式,后面找个专题细讲一下!
		}).start();

线程池详细解析

首先我们来看看线程池的构造函数:

// Public constructors and methods

    
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

我们通过这个图,来理解里面的几个参数:

第一个参数:int corePoolSize 核心线程,上图绿色方框中的内容!
第二个参数:int maximumPoolSize 最大线程,核心线程和非核心线程的总数!
第三个参数:long keepAliveTime 存活时间,非核心线程的存活时间!
第四个参数:TimeUnit unit 存活时间单位,来自JUC中的TimeUnit枚举类!
第五个参数:BlockingQueue workQueue 阻塞队列 可以new 它的实现类,作为这个参数,配置上对应的长度即可 比如:new ArrayBlockingQueue(5) 长度五的阻塞队列!
第六个参数:RejectedExecutionHandler handler 异常处理方式,为红色部分所示!具体使用方式如下图所示,使用例子:new ThreadPoolExecutor.DiscardOldestPolicy()“丢弃老任务(队头)策略”

package com.woniuxy.concurrent.executor;

import java.util.concurrent.*;


public class ExecutorPoolTest1 {
    volatile static int j = 0;

    public static void main(String[] args) {
        
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5000, TimeUnit.MICROSECONDS,
                new ArrayBlockingQueue<>(5), new ThreadPoolExecutor.AbortPolicy());

        for (int i = 1; i <= 16; i++) {
            threadPoolExecutor.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("我是"+Thread.currentThread().getName()+"线程,正在执行" + (++ExecutorPoolTest1.j) +
                            "的任务!");
                    try {
                        Thread.sleep(300);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },i);
        }
    }
}


打印结果:
我是pool-1-thread-1线程,正在执行1的任务!
我是pool-1-thread-4线程,正在执行4的任务!
我是pool-1-thread-2线程,正在执行2的任务!
我是pool-1-thread-3线程,正在执行3的任务!
我是pool-1-thread-5线程,正在执行5的任务!
我是pool-1-thread-6线程,正在执行6的任务!
我是pool-1-thread-7线程,正在执行7的任务!
我是pool-1-thread-8线程,正在执行8的任务!
我是pool-1-thread-9线程,正在执行9的任务!
我是pool-1-thread-10线程,正在执行10的任务!
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@5cad8086 rejected from java.util.concurrent.ThreadPoolExecutor@6e0be858[Running, pool size = 10, active threads = 10, queued tasks = 5, completed tasks = 0]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
	at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:123)
	at com.woniuxy.concurrent.executor.ExecutorPoolTest1.main(ExecutorPoolTest1.java:25)
我是pool-1-thread-7线程,正在执行11的任务!
我是pool-1-thread-4线程,正在执行13的任务!
我是pool-1-thread-10线程,正在执行12的任务!
我是pool-1-thread-5线程,正在执行14的任务!
我是pool-1-thread-8线程,正在执行15的任务!

通过上面这个方法,我们可以看出,如果线程数量正好是15(for循环次数)个线程,则线程池中可以总线程数量为10个,加上5个阻塞队列,正好可以执行15个任务,总共创建10个线程!如果切换异常执行方式,也就是最后一个参数,会有什么区别呢??请自行尝试!

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服