精华内容
下载资源
问答
  • Java多线程之创建任务和线程

    千次阅读 2016-12-14 17:19:47
    Runnable创建线程任务就是对象。为了创建任务,必须首先为任务定义一个类。任务类必须实现Runnable接口。Runnable接口非常简单,它只包含一个run方法。需要实现这个方法来告诉系统线程将如何运行。开发一个任务类的...

    Runnable创建线程

    任务就是对象。为了创建任务,必须首先为任务定义一个类。任务类必须实现Runnable接口。Runnable接口非常简单,它只包含一个run方法。需要实现这个方法来告诉系统线程将如何运行。开发一个任务类的模板如图29-2a所示。
    一旦定义了一个TaskClass,就可以用它的构造方法创建一个任务。例如,

    TaskClass task = new TaskClass(...);

    任务必须在线程中执行。Thread类包括创建线程的构造方法以及控制线程的很多有用的方法。使用下面的语句创建任务的线程:

    Thread thread = new Thread(task);

    然后调用start()方法告诉Java虚拟机该线程准备运行,如下所示:

    thread.start();

    Java虚拟机通过任务的run()方法执行任务。图29-2b概括了创建一个任务,一个线程以及开始线程的主要步骤。
    这里写图片描述
    下面例子给出一个程序,它创建三个任务以及运行这三个任务的线程:

    • 第一个任务打印字母a100次
    • 第二个任务打印字母b100次
    • 第三个任务打印1~100的整数。
      如果运行这个程序,则三个线程将共享CPU,并且在控制台上轮流打印字母和数字。
    package chapter29;
    
    public class TaskThreadDemo 
    {
        public static void main(String[] args)
        {
            //Create tasks
            Runnable printA = new PrintChar('a',100);
            Runnable printB = new PrintChar('b',100);
            Runnable print100 = new PrintNum(100);
    
            //Create threads
            Thread thread1 = new Thread(printA);
            Thread thread2 = new Thread(printB);
            Thread thread3 = new Thread(print100);
    
            //Start threads
            thread1.start();
            thread2.start();
            thread3.start();
        }
    }
    
    //The task for printing a character a specified number of times
    class PrintChar implements Runnable
    {
        private char charToPrint;//The character to print
        private int times;//The number of times to repeat
    
        /*
         * Construct a task with specified character to print
         * times to print the character
         */
        public PrintChar(char c,int t)
        {
            charToPrint = c;
            times = t;
        }
    
        /*
         * Override the run() method to tell the system
         * what task to perform
         */
        public void run()
        {
            for(int i = 0; i < times; i++)
            {
                System.out.println(charToPrint);
            }
        }
    }
    
    //The task class for printing numbers from 1 to n for a given n
    class PrintNum implements Runnable
    {
        private int lastNum;
    
        /*Construct a task for printing 1,2,.....n*/
        public PrintNum(int n)
        {
            lastNum = n;
        }
    
        /*Tell the thread how to run*/
        public void run()
        {
            for(int i = 1; i <= lastNum; i++)
            {
                System.out.println(" " + i);
            }
        }
    }

    该程序创建了三个任务。为了同时运行它们,创建三个线程。调用start()方法启动一个线程,它会导致任务中的run()方法被执行。当run()方法执行完毕,线程就终止。
    因为前两个任务printA和printB有类似的功能,所以它们可以定义在同一个任务类PrintChar中。PrintChar类实现Runnable,并且覆盖run()方法,使之具备打印字符动作。该类提供根据给定次数打印任意单个字符的框架。可运行对象printA和printB都是PrintChar类的实例。
    PrintNum类实现Runnable,并且覆盖run()方法,使之具备打印数字的动作。该类提供对于任意整数n,打印从
    1到n的整数的框架。可运行对象print100是PrintNum类的一个实例。
    注意:如果看不到并发运行三个线程的效果,那么就要增加打印字符的个数。例如:

    Runnable printA = new PrintChar('a',10000);
    package heima;
    
    /*
     * 需求:简单的卖票程序
     * 多个窗口同时买票
     * 
     * 创建线程的第二种方式:实现Runnable接口
     * 
     * 步骤:
     * 1.定义类实现Runnable接口
     * 2.覆盖Runnable接口中的run方法。
     *   将线程要运行的代码存放在该run方法中。
     * 3.通过Thread类建立线程对象。
     * 4.将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
     *   为什么要将Runnable接口的子类对象传递给Thread的构造函数。
     *   因为:自定义的run方法所属的对象是Runnable接口的子类对象
     *   所以要让线程去指定指定对象的run方法。就必须明确该run方法所属对象。
     * 5.调用Thread类的start方法开启线程并调用Runnable接口子类的run方法
     * 
     * 实现方式和继承方式有什么区别呢?
     * 
     * 实现方式好处:避免了单继承的局限性。
     * 在定义线程时,建议使用实现方式。
     * 
     * 两种方式区别:
     * 继承Thread:线程代码存放Thread子类run方法中
     * 实现Runnable,线程代码存在接口的子类的run方法中。
     */
    class Ticket implements Runnable
    {
        private int tick = 100;
        public void run()
        {
            while(true)
            {
                if(tick > 0)
                {
                    System.out.println(Thread.currentThread().getName() + "......sale : " + tick--);
                }
            }
        }
    }
    
    public class TicketThread
    {
        public static void main(String[] args)
        {
            Ticket t = new Ticket();
    
            Thread t1 = new Thread(t);
            Thread t2 = new Thread(t);
            Thread t3 = new Thread(t);
            Thread t4 = new Thread(t);
            t1.start();
            t2.start();
            t3.start();
            t4.start();
            /*Ticket t1 = new Ticket();
            Ticket t2 = new Ticket();
            Ticket t3 = new Ticket();
            Ticket t4 = new Ticket();
    
            t1.start();
            t2.start();
            t3.start();
            t4.start();*/
        }
    }
    

    创建线程的另一种方法:Thread类

    Thread类包含为任务而创建的线程的构造方法,以控制线程的方法。
    这里写图片描述

    步骤:
       1.定义类继承Thread,
       2.复写Thread类中的run方法,
          目的:将自定义代码存储在run方法。让线程运行。
       3.调用线程的start方法,
         该方法两个作用:启动线程,调用run方法
    发现运行结果每一次都不同,
    因为多个线程都获取cpu的执行权,cpu执行到谁,谁就运行。明确一点,在某一时刻,只能有一个程序在运行,(多核除外)
    cpu在做着快速的切换,以达到看上去是同时运行的效果。我们可以形象把多线程的运行认为在互相抢夺cpu的执行权。
    
    这就是多线程的一个特性:随机性,谁抢到谁执行,至于执行多长,cup说了算。
    
    为什么要覆盖run方法呢?
    Thread类用于描述线程
    该类定义了一个功能,用于存储线程要运行的代码。该存储功能就是run方法
    
    也就是说Thread类中的run方法,用于存储线程要运行的代码。
    
    class Demo extends Thread
    {
      public void run()
      {
        for(int x = 0; x < 60; x++)
        {
          System.out.println("demo run----"+x);
        }
      }
    }
    
    class ThreadDemo
    {
      public static void main(String[] args)
      {
        Demo d = new Demo();//创建好一个线程。
        d.start();//开启线程并执行该线程的run方法
        //d.run();//仅仅是对象调用方法,而线程创建了,并没有运行。
    
        for(int x = 0; x < 60; x++)
          System.out.println("Hello World!--" + x);
      }
    }

    这里写图片描述

    /*
    练习:
    创建两个线程,和主线程交替运行。
    */
    class Test extends Thread
    {
      private String name;
      Test(String name)
      {
        this.name = name;
      }
      public void run()
      {
        for (int x = 0; x < 60; x++)
        {
          System.out.println(name + " run..." + x);
        }
      }
    }
    
    public class ThreadTest
    {
      public static void main(String[] args)
      {
        Test t1 = new Test("one");
        Test t2 = new Test("two");
        t1.start();
        t2.start();
        //t1.run();
        //t2.run();
    
        for(int x = 0; x < 60; x++)
        {
          System.out.println("main......" + x);
        }
      }
    }

    线程的运行状态

    这里写图片描述

    获取线程对象及名称

    package heima;
    
    /*
     * 原来线程都有自己默认的名称
     * Thread-编号 该编号从0开始。
     * 
     * static Thread currentThread():获取当前线程对象。
     * getName():获取线程名称
     * 
     * 设置线程名称:setName或者构造函数。
     */
    class Test extends Thread
    {
      private String name;
      Test(String name)
      {
        this.name = name;
      }
      public void run()
      {
        for (int x = 0; x < 60; x++)
        {
          System.out.println((Thread.currentThread() == this) + "..." + this.getName() + " run..." + x);
        }
      }
    }
    
    public class ThreadTest
    {
      public static void main(String[] args)
      {
        Test t1 = new Test("one");
        Test t2 = new Test("two");
        t1.start();
        t2.start();
        //t1.run();
        //t2.run();
    
        for(int x = 0; x < 60; x++)
        {
          System.out.println("main......" + x);
        }
      }
    }
    展开全文
  • java线程池合理设置最大线程数和核心线程数

    千次阅读 热门讨论 2020-10-10 17:13:31
    这个时候就需要使用多线程去处理。 一开始是这么配置的: @Configuration @EnableAsync(proxyTargetClass = true)//利用@EnableAsync注解开启异步任务支持 @ComponentScan({"com.ctfojt.auditbcarslogo.service"}) /...

    工作中有这样一个场景,需要处理千万级别的数据的一个算法,大部分是增删查的操作。这个时候就需要使用多线程去处理。
    一开始是这么配置的:

    @Configuration
    @EnableAsync(proxyTargetClass = true)//利用@EnableAsync注解开启异步任务支持
    @ComponentScan({"com.ctfojt.auditbcarslogo.service"}) //必须加此注解扫描包
    public class ThreadPoolConfig implements AsyncConfigurer {
    
        @Override
        public Executor getAsyncExecutor() {
            ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
            taskExecutor.setCorePoolSize(10);//核心线程大小
            taskExecutor.setMaxPoolSize(20);//最大线程大小
            taskExecutor.setQueueCapacity(500);//队列最大容量
            //当提交的任务个数大于QueueCapacity,就需要设置该参数,但spring提供的都不太满足业务场景,可以自定义一个,也可以注意不要超过QueueCapacity即可
            taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
            taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
            taskExecutor.setAwaitTerminationSeconds(10);
            taskExecutor.setThreadNamePrefix("BCarLogo-Thread-");
            taskExecutor.initialize();
            return taskExecutor;
        }
    }
    

    这样配置效率很低,一天大概能处理30多万的数据。往后随着插入表的数据越来越多,处理速度也随之降低,跑个一两天之后,差不多能够处理10万多。完全满足不了需求。

    后来网上查询线程池核心数配置,大部分都是这样的:

    注:IO密集型(某大厂实践经验)
           核心线程数 = CPU核数 /1-阻塞系数)
    或着
    CPU密集型:核心线程数 = CPU核数 + 1
    IO密集型:核心线程数 = CPU核数 * 2
    

    也尝试着这么配置,结果发现效率并不理想,提高不了多少。

    最后,我是这么配置的,结果效率大大提升,仅用不到一天的数据,就跑完了千万级的数据。

    //获取当前机器的核数
    public static final int cpuNum = Runtime.getRuntime().availableProcessors();
    
    @Override
        public Executor getAsyncExecutor() {
            ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
            taskExecutor.setCorePoolSize(cpuNum);//核心线程大小
            taskExecutor.setMaxPoolSize(cpuNum * 2);//最大线程大小
            taskExecutor.setQueueCapacity(500);//队列最大容量
            //当提交的任务个数大于QueueCapacity,就需要设置该参数,但spring提供的都不太满足业务场景,可以自定义一个,也可以注意不要超过QueueCapacity即可
            taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
            taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
            taskExecutor.setAwaitTerminationSeconds(60);
            taskExecutor.setThreadNamePrefix("BCarLogo-Thread-");
            taskExecutor.initialize();
            return taskExecutor;
        }
    
    

    完美的解决了问题,希望对大家有所帮助!!!

    展开全文
  • Java线程池的核心线程数和最大线程数

    千次阅读 多人点赞 2021-03-14 19:24:35
    而把任务提交给线程池就像是把小球塞进花瓶。 整个过程就像下面这个有趣的动画: 下面我们先来了解一下Java线程池的参数。 希望看完这篇文章后, 再提起线程池的时候, 你脑海首先出现的, 会是一个花瓶 : ) 1...

    Java的线程池就像是一个花瓶容器。

    而把任务提交给线程池就像是把小球塞进花瓶。

    整个过程就像下面这个有趣的动画:

    下面我们先来了解一下Java线程池的参数。

    希望看完这篇文章后, 再提起线程池的时候, 你脑海首先出现的, 会是一个花瓶 : )


    线程池的参数意义

    Java线程池的构造函数如下:

    public ThreadPoolExecutor(
      int corePoolSize,
      int maximumPoolSize,
      long keepAliveTime,
      TimeUnit unit,
      BlockingQueue<Runnable> workQueue,
      ThreadFactory threadFactory,
      RejectedExecutionHandler handler) {
        //...
    }

    线程池有这么几个重要的参数:

    • corePoolSize=> 线程池里的核心线程数量
    • maximumPoolSize=> 线程池里允许有的最大线程数量
    • keepAliveTime=> 空闲线程存活时间
    • unit=> keepAliveTime的时间单位,比如分钟,小时等
    • workQueue=> 缓冲队列
    • threadFactory=> 线程工厂用来创建新的线程放入线程池
    • handler=> 线程池拒绝任务的处理策略,比如抛出异常等策略

    线程池大体的原理就是这样的:corePoolSize ->queue -> maxPoolSzie , 吧啦吧啦......

    那么现在重点来了, 这堆参数解释不看源码真的搞不懂怎么办?

    或者你看懂了这些参数的文字解析,但是到用的时候总是记不住怎么办?

    或者我们来一组实际参数,你能理解这代表的含义吗?

    corePoolSize:1
    mamximumPoolSize:3
    keepAliveTime:60s
    workQueue:ArrayBlockingQueue,有界阻塞队列,队列大小是4
    handler:默认的策略,抛出来一个ThreadPoolRejectException

    别慌,我们可以把线程池的参数做成花瓶的参数,这样一来很多东西就不言自明了。

    线程池的参数可视化

    我们回到前面所说的花瓶。

    这个花瓶由 瓶口 、 瓶颈 、 瓶身 三个部分组成。

    这三个部分分别对应着线程池的三个参数:maximumPoolSize, workQueue,corePoolSize。

    线程池里的线程,我用一个红色小球表示,每来一个任务,就会生成一个小球:

    而核心线程,也就是正在处理中的任务,则用灰色的虚线小球表示 (目前第一版动画先这样简陋点吧......)

    于是画风就变成了这样,“花瓶”有这么几个重要的参数:

    • corePoolSize=> 瓶身的容量
    • maximumPoolSize=> 瓶口的容量
    • keepAliveTime=> 红色小球的存活时间
    • unit=> keepAliveTime的时间单位,比如分钟,小时等
    • workQueue=> 瓶颈,不同类型的瓶颈容量不同
    • threadFactory=> 你投递小球进花瓶的小手 (线程工厂)
    • handler=> 线程池拒绝任务的处理策略,比如小球被排出瓶外

    如果往这个花瓶里面放入很多小球时(线程池执行任务);

    瓶身 (corePoolSize) 装不下了, 就会堆积到 瓶颈 (queue) 的位置;

    瓶颈还是装不下, 就会堆积到 瓶口 (maximumPoolSize);

    直到最后小球从瓶口溢出。

    还记得上面提到的那一组实际参数吗,代表的花瓶大体上是如下图这样的:

    那么参数可视化到底有什么实际意义呢?


    3 阿里的规范

    首先我们来看阿里开发手册中对于 Java 线程池的使用规范:

    为什么规范中提及的四种线程会导致OOM呢?

    我们看看这四种线程池的具体参数,然后再用花瓶动画演示一下导致OOM的原因。

    线程池FixedThreadPool

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
        0L, TimeUnit.MILLISECONDS,
        new LinkedBlockingQueue<Runnable>());

    我们关心的参数如下

    corePoolSize:nThreads
    mamximumPoolSize:nThreads
    workQueue:LinkedBlockingQueue

    FixedThreadPool表示的花瓶就是下图这样子:

    线程池SingleThreadPool:

    public static ExecutorService newSingleThreadExecutor() {
          return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
             0L, TimeUnit.MILLISECONDS,
             new LinkedBlockingQueue<Runnable>()));
    ​  }

    我们关心的参数如下

    corePoolSize:1
    mamximumPoolSize:1
    workQueue:LinkedBlockingQueue

    SingleThreadPool表示的花瓶就是下图这样子:


    虽然两个线程池的样子没什么差异,但是这里我们发现了一个问题:

    为什么 FixedThreadPool 和 SingleThreadPool 的 corePoolSize和mamximumPoolSize 要设计成一样的?

    回答这个问题, 我们应该关注一下线程池的 workQueue 参数。

    线程池FixedThreadPool和SingleThreadPool 都用到的阻塞队列 LinkedBlockingQueue。

    LinkedBlockingQueue

    The capacity, if unspecified, is equal to {@link Integer#MAX_VALUE}. Linked nodes are dynamically created upon each insertion unless this would bring the queue above capacity.

    从LinkedBlockingQueue的源码注释中我们可以看到, 如果不指定队列的容量, 那么默认就是接近无限大的。

    从动画可以看出, 花瓶的瓶颈是会无限变长的, 也就是说不管瓶口容量设计得多大, 都是没有作用的!

    所以不管线程池FixedThreadPool和SingleThreadPool 的mamximumPoolSize 等于多少, 都是不生效的!


    线程池CachedThreadPool

    public static ExecutorService newCachedThreadPool() {
      return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
      60L, TimeUnit.SECONDS,
      new SynchronousQueue<Runnable>());

    我们关心的参数如下

    corePoolSize:0
    mamximumPoolSize:Integer.MAX_VALUE
    workQueue:SynchronousQueue

    表示的花瓶就是下图这样子:

    这里我们由发现了一个问题:

    为什么CachedThreadPool的mamximumPoolSize要设计成接近无限大的?

    回答这个问题, 我们再看一下线程池CachedThreadPool的 workQueue 参数:SynchronousQueue。

    SynchronousQueue

    来看SynchronousQueue的源码注释:

    A synchronous queue does not have any internal capacity, not even a capacity of one.

    从注释中我们可以看到, 同步队列可以认为是容量为0。

    所以如果mamximumPoolSize不设计得很大, 就很容易导致溢出。

    但是瓶口设置得太大,堆积的小球太多,又会导致OOM(内存溢出)。

    线程池ScheduledThreadPool

    public ScheduledThreadPoolExecutor(int corePoolSize) {
      super(corePoolSize, Integer.MAX_VALUE, 
      0, NANOSECONDS,
      new DelayedWorkQueue());
    }

    我们关心的参数如下

    corePoolSize:corePoolSize
    mamximumPoolSize:Integer.MAX_VALUE
    workQueue:DelayedWorkQueue

    可以看到, 这里出现了一个新的队列 workQueue:DelayedWorkQueue

    DelayedWorkQueue

    DelayedWorkQueue 是无界队列, 基于数组实现, 队列的长度可以扩容到 Integer.MAX_VALUE。

    同时ScheduledThreadPool的 mamximumPoolSize 也是接近无限大的。

    可以想象得到,ScheduledThreadPool就是史上最强花瓶, 极端情况下长度已经突破天际了!

    到这里, 相信大家已经明白, 为什么这四种线程会导致OOM了。

    怎么感觉这四种线程还真是名副其实的“花瓶”呢 :)


    后续

    目前花瓶动画还只是粗略的版本, 有部分瑕疵是不可避免的, 根据二八定律, 我的主要想法大体上是先做出来了,剩下的细节再慢慢补。

    目前只体现了线程池的三个参数。

    如果现在加入参数 keepAliveTime, 那么动画又会有什么效果的呢?

    敬请期待后续更新的文章。


    可视化的意义

    有很多人或许会认为, 学习个线程池, 还要做什么动画, 这不是走偏了吗?

    引用大神的一句话回答这个问题:

    Data visualization knowledge is not necessary -- just the desire to spread some knowledge.

    —— Ben Johnson

    数据可视化确实不是必需的, 但是有时候我们仅仅只是渴望给大家分享一些知识。

    而且在这个分享的过程中, 动画会让你做出更多的思考:

    思考动画怎么才能符合真实场景的效果。

    比如当我们开始思考,动画中花瓶颈部的长度变化,以及DelayedWorkQueue队列容量的变化,这两者如何才能对应的上时,于是不可避免的, 我们会开始研究起DelayedWorkQueue的扩容方式

    甚至每一种队列都可以单独展开做成更加细化的动画。

    而想要做好这些动画, 又要开始研究不同队列的源码了, 有需求才有动力!

    /**
     * 简单配置示例
     */
    
    //获取当前机器的核数
    public static final int cpuNum = Runtime.getRuntime().availableProcessors();
    
    @Override
        public Executor getAsyncExecutor() {
            ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
            taskExecutor.setCorePoolSize(cpuNum);//核心线程大小
            taskExecutor.setMaxPoolSize(cpuNum * 2);//最大线程大小
            taskExecutor.setQueueCapacity(500);//队列最大容量
            //当提交的任务个数大于QueueCapacity,就需要设置该参数,但spring提供的都不太满足业务场景,可以自定义一个,也可以注意不要超过QueueCapacity即可
            taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
            taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
            taskExecutor.setAwaitTerminationSeconds(60);
            taskExecutor.setThreadNamePrefix("BCarLogo-Thread-");
            taskExecutor.initialize();
            return taskExecutor;
        }
    
    

     

    展开全文
  • Java线程池核心线程数与最大线程数的区别

    万次阅读 多人点赞 2020-06-23 15:20:45
    第一步: 先判断线程池中当前线程数量是否达到了corePoolSize,若未达到,则新建线程运行此任务,且任务结束后将该线程保留在线程池中,不做销毁处理,若当前线程数量已达到corePoolSize,则进入下一步; 第二步: ...

    线程池策略

    corePoolSize:核心线程数;maximunPoolSize:最大线程数
    每当有新的任务到线程池时,
    第一步: 先判断线程池中当前线程数量是否达到了corePoolSize,若未达到,则新建线程运行此任务,且任务结束后将该线程保留在线程池中,不做销毁处理,若当前线程数量已达到corePoolSize,则进入下一步;
    第二步: 判断工作队列(workQueue)是否已满,未满则将新的任务提交到工作队列中,满了则进入下一步;
    第三步: 判断线程池中的线程数量是否达到了maxumunPoolSize,如果未达到,则新建一个工作线程来执行这个任务,如果达到了则使用饱和策略来处理这个任务。注意: 在线程池中的线程数量超过corePoolSize时,每当有线程的空闲时间超过了keepAliveTime,这个线程就会被终止。直到线程池中线程的数量不大于corePoolSize为止。
    (由第三步可知,在一般情况下,Java线程池中会长期保持corePoolSize个线程。)

    饱和策略

    当工作队列满且线程个数达到maximunPoolSize后所采取的策略
    AbortPolicy:默认策略;新任务提交时直接抛出未检查的异常RejectedExecutionException,该异常可由调用者捕获。
    CallerRunsPolicy:既不抛弃任务也不抛出异常,使用调用者所在线程运行新的任务。
    DiscardPolicy:丢弃新的任务,且不抛出异常。
    DiscardOldestPolicy:调用poll方法丢弃工作队列队头的任务,然后尝试提交新任务
    自定义策略:根据用户需要定制。

    展开全文
  • 线程数=CPU可用核心/(1 - 阻塞系数) 其中阻塞系数在01之间。 计算密集型任务的阻塞系数为0,而IO密集型任务的阻塞系统则接近1.
  • 线程(一):创建线程和线程的常用方法

    万次阅读 多人点赞 2018-09-01 19:14:23
    一:为什么要学多线程 应付面试 :多线程几乎是面试中必问的题,所以掌握一定的基础知识是必须的。 了解并发编程:实际工作中很少写多线程的代码,这部分代码一般都被人封装起来了,在业务中使用多线程的机会也...
  • 1、说说轮巡任务调度与抢占式任务调度的区别? 答:轮询任务调度与抢占式任务调度的区别在于...2当软件线程超过硬件线程的时候,支持抢占式多任务处理的操作系统一般会采用时间片轮转调度的方案。 3 对于RTO
  • CPU个,核心线程数

    万次阅读 多人点赞 2018-08-14 09:29:07
    我们在买电脑的时候,经常会看cpu的参数,对cpu的描述有这几种:“双核”、“双核四线程”、“四核”、“四核四线程”、“四核八线程”……。 我们接触的电脑基本上都只有一个cup。cpu的个数很容易得到,螺丝刀拆开...
  • 近期看了一些JVM和并发编程的知识,来做一个关于(线程池线程数与(CPU密集型任务和I/O密集型任务)的关系)的总结: 1.任务类型举例: 1.1: CPU密集型: 例如,一般我们系统的静态资源,比如js,css等,会存在一个版本号,如 ...
  • 线程线程数设置多少合适

    千次阅读 2020-06-30 01:15:04
    线程数的设置的最主要的目的是为了充分并合理地使用 CPU 内存等资源,从而最大限度地提高程序的性能,因此让我们一起去探索吧! 首先要考虑到 CPU 核心,那么在 Java 中如何获取核心线程数? 可以使用 Runtime....
  • 查看CPU的核心线程数

    千次阅读 2019-07-08 10:27:33
    方法一:进入系统的任务管理器:点击“性能”标签,找到CPU项,如下图所示: 注意:设备管理器中的处理器数量为线程数: ...方法二:下载CPU-Z 工具可以看到CPU的核心数和线程数,如下图所示: ...
  • 如何查看服务器CPU核心数和线程数

    千次阅读 2019-10-02 14:54:26
    知道服务器CPU型号,那么我们如何在服务器里面查看服务器CPU核心数和线程数呢?步骤:先用鼠标右键点击屏幕最下方的任务栏空白处。会弹出一个菜单。 在菜单中用鼠标左键点选“启动任务管理器”。点击任务管理器的...
  • 线程、进程、多线程、多进程 任务 小结

    千次阅读 多人点赞 2019-04-20 11:59:56
    6 线程和进程的区别 7 进程的优缺点 7.1 进程的优点 7.2 进程的缺点 8 线程的优缺点 8.1 线程的优点 8.2 线程的缺点 9 多线程的优缺点 9.1 多线程的优点 9.2 多线程的缺点 10多进程的优缺点 10.1 多进程...
  • 鸿蒙开发核心之线程讲解一、简单说明二、任务分发器① GlobalTaskDispatcher② ParallelTaskDispatcher③ SerialTaskDispatcher④ SpecTaskDispatcher⑤ 同步派发任务(syncDispatch)⑥ 异步派发任务(asyncDispatch)...
  • cpu个、核数、线程数、Java多线程关系的理解

    万次阅读 热门讨论 2017-12-08 15:35:37
    一 cpu个、核数、线程数的关系 cpu个:是指物理上,也及硬件上的核心...二 cpu线程数和Java多线程 首先明白几个概念: (1) 单个cpu线程在同一时刻只能执行单一指令,也就是一个线程。 (2) 单个线程同时只能...
  • 任务处理线程需要不断地从任务队列里取任务执行; 任务处理线程需要有一个标记,标记线程什么时候应该停止。 Pool 存放多个任务处理线程; 负责多个线程的启停; 管理向线程池的提交任务,下发给线程去执行。 ...
  • Linux系统编程——多线程实现多任务

    万次阅读 2015-06-10 18:00:27
    每个进程都拥有自己的数据段、代码段堆栈段,这就造成进程在进行创建、切换、撤销操作时,需要较大的系统开销。为了减少系统开销,从进程中演化出了线程。...更多详情,请看《进程和线程的区别与联系》。
  • java多线程均摊任务

    万次阅读 2019-08-01 16:11:07
    线程平均执行任务 学习记录 代码如下: public static void main(String[] args) { Date startDate = new Date(); try { //创建一个任务提供给线程 List<String> list = new ArrayList<>(...
  • 在指定的CEF线程上执行任务

    千次阅读 2016-02-16 13:05:03
    CEF有几种线程,比如TID_UI、比如TID_RENDER,我们可以指定某个任务在某个线程上执行。
  • 线程之Task(任务

    万次阅读 多人点赞 2018-11-12 15:44:30
    任务和线程的区别: 1、任务是架构在线程之上的,也就是说任务最终还是要抛给线程去执行。 2、任务跟线程不是一对一的关系,比如开10个任务并不是说会开10个线程,这一点任务有点类似线程池,但是任务相比线程池...
  • Java中有多个线程在执行任务,这时候关闭Tomcat,线程任务会立即结束么?在这种情况下,自己创建的线程线程池会有所区别么?
  • 当程序的执行效率要求较高时,可以考虑多线程技术,在使用多线程之前,需要我们了解自己的电脑或者服务器的CPU线程数量,线程数量与CPU核数有关系,因此如何查看电脑服务器的CPU核数与线程数将是我们运用多线程...
  • Spring Boot 定时任务线程和线程

    万次阅读 多人点赞 2018-03-01 14:46:21
    Spring Boot 的定时任务: 第一种:把参数配置到.properties文件中: 代码: package com.accord.task; import java.text.SimpleDateFormat; import java.util.Date; import org.springframework.scheduling....
  • 线程启动线程数计算公式

    千次阅读 2018-01-01 21:15:49
    启动线程数 = 【任务执行时间/(任务执行时间-IO等待时间)】*CPU内核
  • JAVA多线程——实现任务分发

    千次阅读 2018-04-10 10:28:31
    本文代码来自网络,我自己按理解重新贴一下...想要实现的效果如下:线程1执行任务第0——24 线程2执行任务第25——49 线程3执行任务第50——74 线程4执行任务75——99具体实现方法如下。包含三个类:任务分发类、...
  • 线程池动态调整线程数

    千次阅读 2019-09-09 16:12:08
    领导要动态实时调整任务线程数,这真的是个什么烂需求,线程数不是应该根据cpu资源来评估调的最优值吗,但是领导既然说了,硬着头皮也得弄啊,还是具体研究一下,不能做也得给出个理由啊... 按照JDK文档的描述, ...
  • 在我们平时的编码过程中,有时候会想到用多线程来提升程序的性能,那么什么时候用多线程,多线程线程数应该设置为多少比较好,这个就需要根据具体的需求来设置,这里,主要分为CPU密集型IO密集型的任务。...
  • CPU的核心线程数的关系区别

    万次阅读 2018-01-31 15:16:35
    ------------------------------------- 我们在选购电脑的时候,CPU是一个需要考虑到核心因素,因为它决定了电脑的性能等级。...CPU除了核心之外,还有线程数之说,下面笔者就来解释一下CPU的核心
  • 线程并行处理定时任务时,Timer运行多个TimeTask时,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行,使用ScheduledExecutorService则没有这个问题。  建议多线程-任务调度,使用如下方式: 首先...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 750,623
精华内容 300,249
关键字:

线程数和任务