- public static void main(String[] args) {
- System.out.println("main .... statt");
- new Thread01().start();
- System.out.println("main ... end");
- }
- public static class Thread01 extends Thread{
- @Override
- public void run() {
- System.out.println("当前线程:"+Thread.currentThread().getId());
- int i = 10 / 2;
- System.out.println("运行结果:"+ i);
- }
- }
运行结果
- public static class Runable01 implements Runnable{
- @Override
- public void run() {
- System.out.println("当前线程:"+Thread.currentThread().getId());
- int i = 10 / 2;
- System.out.println("运行结果:"+ i);
- }
- }
- public static void main(String[] args) {
- System.out.println("main .... statt");
- //new Thread01().start();
- Runable01 runable01 = new Runable01();
- new Thread(runable01).start();
- System.out.println("main ... end");
- }
该方法是可以获取线程执行结果的。
- public static class Callable01 implements Callable<Integer> {
- @Override
- public Integer call() throws Exception {
- System.out.println("当前线程:"+Thread.currentThread().getId());
- int i = 10 / 2;
- System.out.println("运行结果:"+ i);
- return i;
- }
- }
- public static void main(String[] args) {
- System.out.println("main .... start");
- //new Thread01().start();
-
- //Runable01 runable01 = new Runable01();
- //new Thread(runable01).start();
-
- Callable01 callable01 = new Callable01();
- FutureTask
task = new FutureTask(callable01); - new Thread(task).start();
-
- System.out.println("main ... end");
- }
但是,使用Callable是可以获取线程的返回结果的。
- public static void main(String[] args) throws ExecutionException, InterruptedException {
- System.out.println("main .... start");
- //new Thread01().start();
-
- //Runable01 runable01 = new Runable01();
- //new Thread(runable01).start();
-
- Callable01 callable01 = new Callable01();
- FutureTask<Integer> task = new FutureTask<Integer>(callable01);
- new Thread(task).start();
- Integer integer = task.get();
- System.out.println("返回结果为===="+integer);
-
- System.out.println("main ... end");
- }
执行结果:
虽然有了异步线程,但是代码还是从上往下执行,原因就是线程调用了fuutetask的get方法是阻塞式等待。
如果我们后来的业务逻辑非常多,都写我们的原生代码,new Thread().start();问题是非常大的。这就代表我们公司有新任务,就招聘一名员工。任务多了之后,最终会将资源(内存,堆,栈)耗尽。
我们以后在业务代码里边,以上三种启动线程的方式我们都不用。应该将所有的多线程异步任务,都交给线程池来执行处理。(公司就50个员工,以后什么活就分配给这50个员工中的某一个,当然如果这个人有活,就等他处理完了,再处理新任务。达到了资源控制。)
1、降低资源的消耗
通过重复利用已经创建好的线程降低线程创建和销毁带来的损耗;
2、提高响应速度
因为线程池中的线程数没有超过线程池的最大上限时,有的线程处于等待分配的状态,当任务来的时候,无需创建新的线程就能执行,节省了线程创建的时间。
3、提高线程的可管理性
线程池会根据当前系统特点,对池内的线程进行优化处理,减少创建和销毁带来的系统开销。无限的创建和销毁不仅消耗系统资源,还降低系统的稳定性。
JUC里边有个最快的方式得到线程池,
ExecutorService pool = Executors.newFixedThreadPool(10);
当然,这个线程池应该是整个系统一个线程池,而不是每次都创建一个线程池。
线程池执行的方法调用如下:
- // pool.submit(new Runable01());
- pool.execute(new Runable01());
区别如下:
execute的方法类型是void。submit有返回结果。
返回结果:
1、Executors类
2、原生线程池
- ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor();
- //JDK源码
- public ThreadPoolExecutor(int corePoolSize, //核心线程数[一直存在,除非设置了核心线程超时销毁的属性-allowCoreThreadTimeOut]:线程池创建好以后,就准备就绪的线程数量,等待接收异步任务去执行。只是new了几个Thread,但是并没有start();
- int maximumPoolSize, //线程池的最大线程数量,控制资源并发。
- long keepAliveTime, //存活时间:当我们线程数量大于核心线程数量的时候,只有线程空闲大于指定的最大存活时间,非核心线程释放。
- TimeUnit unit,
- BlockingQueue
workQueue,//阻塞队列,如果任务有很多,把(总的异步任务数量-最大线程数量),放入到队列里边。只要线程空闲了,就去队列里边取出新的任务,继续执行。 - ThreadFactory threadFactory,//创建线程的工厂,默认的。
- RejectedExecutionHandler handler) { //如果队列满了,按照指定的拒绝策略,拒绝执行我们的任务。
- if (corePoolSize < 0 ||
- maximumPoolSize <= 0 ||
- maximumPoolSize < corePoolSize ||
- keepAliveTime < 0)
- throw new IllegalArgumentException();
- if (workQueue == null || threadFactory == null || handler == null)
- throw new NullPointerException();
- this.corePoolSize = corePoolSize;
- this.maximumPoolSize = maximumPoolSize;
- this.workQueue = workQueue;
- this.keepAliveTime = unit.toNanos(keepAliveTime);
- this.threadFactory = threadFactory;
- this.handler = handler;
- }
1、线程池创建好,准备好core数量的核心线程,准备接受任务。
2、 新的任务进来,用core准备好空闲线程执行。
(1)core满了,就将新进来的线程放入到阻塞队列中去,空闲的core就会自己去阻塞队列获取任务执行。
(2)阻塞队列满了,就直接开新线程执行,最大只能开到max的执行数量。
(3)max都执行好了,max-core数量空闲的线程会在keepAliveTime指定的时间后,自动销毁,最终保持到core大小。
(4)如果线程开到了max的数量,还有新任务进来,就会使用reject指定的拒绝策略进行处理。
1、可以丢弃
2、可以同步执行。new thread().start()是异步的。
AbortPolicy:抛弃策略;抛出异常;
DiscartPolicy:抛弃策略,不抛出异常;
CallerRunsPlicy:的run()是同步执行的,只有new Thread().start()才是异步执行的。
3、所有的线程都是由指定的factory创建的。
- ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
- 5,
- 200,
- 10,
- TimeUnit.SECONDS,
- new LinkedBlockingDeque<>(10000),//不指定的话,默认是Integer的最大值。一直占用内存。
- Executors.defaultThreadFactory(),
- new ThreadPoolExecutor.AbortPolicy()//丢弃策略
- );
- Executors.newCachedThreadPool();//核心线程数量是0个,但是最大线程数很大,60秒不用就回收
- public static ExecutorService newCachedThreadPool() {
- return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
- 60L, TimeUnit.SECONDS,
- new SynchronousQueue
()); - }
- Executors.newFixedThreadPool();//最大线程数=核心线程数,核心线程从阻塞队列中取任务。阻塞队列满了不会创建非核心线程。
- public static ExecutorService newFixedThreadPool(int nThreads) {
- return new ThreadPoolExecutor(nThreads, nThreads,
- 0L, TimeUnit.MILLISECONDS,
- new LinkedBlockingQueue
()); - }
- Executors.newScheduledThreadPool(); //可以存放定时延期执行的任务线程
- public ScheduledThreadPoolExecutor(int corePoolSize) {
- super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
- new DelayedWorkQueue());
- }
- Executors.newSingleThreadExecutor() //核心线程=最大线程=1,线程执行完毕一个,就从阻塞队列中获取一个任务。
- public static ExecutorService newSingleThreadExecutor() {
- return new FinalizableDelegatedExecutorService
- (new ThreadPoolExecutor(1, 1,
- 0L, TimeUnit.MILLISECONDS,
- new LinkedBlockingQueue
())); - }
由此可见,方式1和方式2,都是异步的,主线程是无法获取到其他线程的结果的。
FutureTask不仅可以接收callable参数,Runable参数也是可以接收的。
JDK源码如下:
- public FutureTask(Callable
callable) { - if (callable == null)
- throw new NullPointerException();
- this.callable = callable;
- this.state = NEW; // ensure visibility of callable
- }
-
- public FutureTask(Runnable runnable, V result) {
- this.callable = Executors.callable(runnable, result);
- this.state = NEW; // ensure visibility of callable
- }
runable方法配合futureTask实现返回值也是可以的,把返回值配置到result对象里边即可。