java多线程

java常见线程创建启动

在Java开发中常用的线程启动有四种

  1. 继承Thread类,并重写run()方法 通过start()调用
  2. 实现Runnable接口并实现run()方法 通过new Thread(myThread2).start()调用
  3. 继承Callable接口并实现call()方法,通过 new Thread(new FutureTask(myThread3)).start()方式启动
  4. 通过线程池创建线程并启动,通常使用 Executors下的静态方法(如Executors.newFixedThreadPool(3))创建线程池,并使用 Executor::execute()方法加入线程
public class ThreadTest {

    private static int POOL_NUM = 10;     //线程数量

    //private static AtomicInteger num = new AtomicInteger(0);
    private static Integer num = new Integer(0);

    private static Object lock = new Object();

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("执行main线程:"+Thread.currentThread().getName());

        MyThread myThread = new MyThread();
        myThread.start();

        Runnable myThread2 = new MyThread2();
        Thread thread = new Thread(myThread2);
        thread.start();

        Callable myThread3 = new MyThread3();
        for (int i = 0; i < 4; i++) {
            FutureTask<Integer> task = new FutureTask<Integer>(myThread3);
            Thread thread1 = new Thread(task);
            thread1.start();
            System.out.printf("执行Callable子线程的返回值:%d\n",task.get());
        }

        //通过线程池创建线程
        ExecutorService executorService = Executors.newFixedThreadPool(3);//设置现线程池大小
        for (int i = 0; i < POOL_NUM; i++) {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("通过线程池创建的线程:"+Thread.currentThread().getName());
                }
            });
        }

    }

    //方式1  继承Thread类,并重写run()方法 通过start()调用
    static class MyThread extends Thread{
        @Override
        public void run() {
            System.out.println("执行Thread子线程:"+Thread.currentThread().getName());
        }
    }

    //方式2 实现Runnable接口并实现run()方法  通过new Thread(myThread2).start()调用
    static class MyThread2 implements Runnable{

        @Override
        public void run() {
            System.out.println("执行Runnable子线程:"+Thread.currentThread().getName());
            //throw  new RuntimeException("Runnable子线程抛出异常");  //异常无法抛出到线程外
        }
    }

    //方式3 继承Callable接口并实现call()方法,通过 new Thread(new FutureTask(myThread3)).start()方式启动
    static class MyThread3 implements Callable<Integer>{
        int i;
        @Override
        public Integer call() throws Exception {
            System.out.println("执行Callable子线程:"+Thread.currentThread().getName());
            return ++i;
        }
    }

}
继承Thread类
  • 优点:使用简单,继承Thread类后可直接new对象并调用start()方法启动线程。
  • 缺点:因为java单继承的关系,继承Thread类后就没有办法继承其他类,这样使得类的扩展性降低。且没有返回值,无法抛出异常。
实现Runnable接口
  • 优点:因为是接口原因,所以不会限制实现类的可扩展性,且Thread本身也是继承了Runnable接口。
  • 缺点:没有返回值,无法抛出异常。实现后依然需要使用Thread启动线程。
继承Callable接口
  • 优点:有返回值,且可以抛出异常。
  • 缺点:调用略微有一些麻烦。
通过线程池创建线程并启动

通常使用Executors类创建线程池,其主要职责就是创建线程池。
在这里插入图片描述
其中包含四种主要线程池:

  1. newSingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。在这里插入图片描述

  2. newFixedThreadPool:创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。在这里插入图片描述

  3. newScheduledThreadPool:创建一个可定期或者延时执行任务的定长线程池,支持定时及周期性任务执行。在这里插入图片描述在这里插入图片描述

  4. newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。在这里插入图片描述
    这里可以发现四种常用的线程池其最终实现都是由ThreadPoolExecutor实现。这就不得不提到ThreadPoolExecutor了

ThreadPoolExecutor

ThreadPoolExecutor是Executor线程池创建接口的实现类,其特点是构造函数提供了创建线程池所需要的7个参数:
在这里插入图片描述

  1. corePoolSize:核心线程数
    • 核心线程会一直存活,及时没有任务需要执行
    • 当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理
    • 设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭
  2. maxPoolSize:最大线程数
    • 当线程数>=corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务
    • 当线程数=maxPoolSize,且任务队列已满时,线程池会采用拒绝策略处理
  3. keepAliveTime:线程空闲时间
    • 当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数量=corePoolSize
    • 如果allowCoreThreadTimeout=true,则会直到线程数量=0
  4. TimeUnit unit:表示keepAliveTime的单位:
  5. workQueue:任务队列容量(阻塞队列)
    • 当核心线程数达到最大时,新任务会放在队列中排队等待执行
  6. threadFactory:指定创建线程的工厂
  7. handler:任务拒绝处理器
    • 两种情况会拒绝处理任务:
      • 当线程数已经达到maxPoolSize,切队列已满,会拒绝新任务
      • 当线程池被调用shutdown()后,会等待线程池里的任务执行完毕,再shutdown。如果在调用shutdown()和线程池真正shutdown之间提交任务,会拒绝新任务,线程池会调用rejectedExecutionHandler来处理这个任务。如果没有设置默认是AbortPolicy,会抛出异常

注意:allowCoreThreadTimeout:允许核心线程超时,是ThreadPoolExecutor的属性之一

这七个参数中重点注意两个点:workQueue和handler

  1. workQueue:任务队列有很多种实现方式,各有不同,随使用者抉择。其中重点说3个ThreadPoolExecutor线程池的API文档中推荐使用的
    • SynchronousQueue :(不存储元素的阻塞队列)每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于 阻塞状态,
      吞吐量通常要高于LinkedBlockingQueue
      静态工厂方法 Executors.newCachedThreadPool 使用了这个队列。
    • LinkedBlockingQueue:(基于单向链表的无界的阻塞队列,尾部插入元素,头部取出元素)可以指定容量,也可以不指定容量。由于它具有“无限容量”的特性,所以可以看作位无界队列。
    • ArrayBlockingQueue:(基于数据结构的有界的阻塞队列)基于数组结构的有界阻塞队列。按 FIFO(先进先出)原则对元素进行操作。尾部插入元素,头部取出元素。这是一个典型的“有界缓存区”,数组的大小一旦固定,就不能再增加其容量。试图向 已满队列 中放入元素会导致操作受阻塞;试图从 空队列 中提取元素将导致类似阻塞。

剩余的队列实现可在源码中查看
在这里插入图片描述
2. handler:拒绝策略,在线程池已满且任务队列已满的情况加,采用阻塞策略,阻塞策略一共有四种
在这里插入图片描述

  • AbortPolicy:直接抛出异常(默认)
    在这里插入图片描述
  • CallerRunsPolicy:直接使用当前线程执行次任务
    在这里插入图片描述
  • DiscardOldestPolicy:讲任务队列中第一个丢弃,新任务加入到任务队列
    在这里插入图片描述
  • DiscardPolicy:什么都不做
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕业设计,基于SpringBoot+Vue+MySQL开发的纺织品企业财务管理系统,源码+数据库+毕业论文+视频演示 在如今社会上,关于信息上面的处理,没有任何一个企业或者个人会忽视,如何让信息急速传递,并且归档储存查询,采用之前的纸张记录模式已经不符合当前使用要求了。所以,对纺织品企业财务信息管理的提升,也为了对纺织品企业财务信息进行更好的维护,纺织品企业财务管理系统的出现就变得水到渠成不可缺少。通过对纺织品企业财务管理系统的开发,不仅仅可以学以致用,让学到的知识变成成果出现,也强化了知识记忆,扩大了知识储备,是提升自我的一种很好的方法。通过具体的开发,对整个软件开发的过程熟练掌握,不论是前期的设计,还是后续的编码测试,都有了很深刻的认知。 纺织品企业财务管理系统通过MySQL数据库与Spring Boot框架进行开发,纺织品企业财务管理系统能够实现对财务人员,员工,收费信息,支出信息,薪资信息,留言信息,报销信息等信息的管理。 通过纺织品企业财务管理系统对相关信息的处理,让信息处理变的更加的系统,更加的规范,这是一个必然的结果。已经处理好的信息,不管是用来查找,还是分析,在效率上都会成倍的提高,让计算机变得更加符合生产需要,变成人们不可缺少的一种信息处理工具,实现了绿色办公,节省社会资源,为环境保护也做了力所能及的贡献。 关键字:纺织品企业财务管理系统,薪资信息,报销信息;SpringBoot
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值