Java多线程小结

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java多线程小结相关的知识,希望对你有一定的参考价值。

JAVA实现多线程的方式有两种,继承Thread,实现Runnable,

  但在JDK1.5之后又有一种新的方式:实现Callable<V>接口

package Test2016.demo;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Demo9 {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        
        ExecutorService executors = Executors.newFixedThreadPool(5);
        
        long start = System.currentTimeMillis();
        
        /**
        List<Future<Integer>> futures = new ArrayList<Future<Integer>>(10);
        
        for (int i = 1; i <= 10; i++) {
            futures.add(executors.submit(new MyTask1(i)));
        }
        
        for (Future<Integer> future : futures) {
            Integer result = future.get();
            
            System.out.println("线程:" + result + "执行完毕!!!");
        }
        */

        CompletionService<Integer> completionServices = new ExecutorCompletionService<Integer>(executors);
        
        for (int i = 1; i <= 10; i++) {
            completionServices.submit(new MyTask1(i));
        }
        
        for (int i = 1; i <= 10; i++) {
            Integer result = completionServices.take().get();
            
            System.out.println("线程:" + result + "执行完毕!!!");
        }
        
        long end = System.currentTimeMillis();
        
        System.out.println("本次共历时:" + (end - start) / 1000 + "秒");
        
        executors.shutdown();  //必须手动关闭线程池
    }
}


class MyTask1 implements Callable<Integer> {
    
    private int taskNum;
    
    public MyTask1(int num) {
        this.taskNum = num;
    }

    @Override
    public Integer call() throws Exception {

        System.out.println("执行线程:" + taskNum);
        Thread.sleep(1000);
        return taskNum;
    }
    
}

执行结果:

Future:                

技术分享                   

 

CompletionService:

技术分享

 

使用Future接口获取任务的状态,按照的是线程的执行顺序来返回结果,即:先执行先获取结果

使用CompletionService接口来获取任务的状态,按照的是执行结束的顺序获取对应的结果,即:先结束先获取结果

  EG:如果两个线程,线程1先执行,线程2后执行,但是线程1执行完需要100s,线程2执行完需要1s,

    如果使用Future获取结果状态:

      线程1 complete!!!

      线程2 complete!!!

    如果使用CompletionService获取结果状态:

      线程2 complete!!!

      线程1 complete!!!

 

附:ExecutorService接口(源码:public interface ExecutorService extends Executor{  })创建线程池方式:

  技术分享

 


 

ThreadPoolExecutor实现线程池
  ThreadPoolExecutor类是ExecutorService接口的一个实现类 
    源码:public class ThreadPoolExecutor extends AbstractExecutorService { }
        public abstract class AbstractExecutorService implements ExecutorService { }
package Test2016.demo;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Demo8 {

    public static void main(String[] args) {

        /**
         * corePoolSize : 线程池维护线程的最少数量
         * maximumPoolSize : 线程池维护线程的最大数量
         * keepAliveTime : 线程池维护线程所允许的空闲时间
         * unit : 线程池维护线程所允许的空闲时间的单位
         * workQueue : 线程池所使用的缓冲队列
         * handler : 线程池对拒绝任务的处理策略
         * */
        ThreadPoolExecutor executor = new ThreadPoolExecutor(15, 50, 200, TimeUnit.NANOSECONDS, new ArrayBlockingQueue<Runnable>(15));
        
        for (int i = 1; i <= 50; i++) {
            MyTask myTask = new MyTask(i);
            
            executor.execute(myTask);
            
             System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+
                     executor.getQueue().size()+",已执行完别的任务数目:"+executor.getCompletedTaskCount());
        }
        executor.shutdown();
    }
}


class MyTask implements Runnable {

    private int taskNum;
    
    public MyTask(int num) {
        this.taskNum = num;
    }
    
    @SuppressWarnings("static-access")
    public void run() {
        System.out.println("正在执行task:" + taskNum);
        
        try {
            Thread.currentThread().sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("task "+taskNum+"执行完毕");
    }
    
}

1、corePoolSize:核心池的大小,这个参数跟后面讲述的线程池的实现原理有非常大的关系。

  在创建了线程池后,默认情况下,线程池中并没有任何线 程,而是等待有任务到来才创建线程去执行任务,

  除非调用了prestartAllCoreThreads()或者 prestartCoreThread()方法,从这2个方法的名字就可以看出,是预创建线程的意思,

  即在没有任务到来之前就创建 corePoolSize个线程或者一个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,

  就会创建一个线程去执行任务,当线 程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;

2、maximumPoolSize:线程池最大线程数,这个参数也是一个非常重要的参数,它表示在线程池中最多能创建多少个线程;

3、keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。

  默认情况下,只有当线程池中的线程数大于corePoolSize 时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,

  即当线程池中的线程数大于corePoolSize 时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。

  但是如果调用了 allowCoreThreadTimeOut(boolean)方法,

  在线程池中的线程数不大于corePoolSize 时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;

4、unit:参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性:

TimeUnit.DAYS;               //
TimeUnit.HOURS;             //小时
TimeUnit.MINUTES;           //分钟
TimeUnit.SECONDS;           //
TimeUnit.MILLISECONDS;      //毫秒
TimeUnit.MICROSECONDS;      //微妙
TimeUnit.NANOSECONDS;       //纳秒

5、workQueue:一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响,

          一般来说,这里的阻塞队列有以下几种选择:

ArrayBlockingQueue;
LinkedBlockingQueue;
SynchronousQueue;

  ArrayBlockingQueue和PriorityBlockingQueue使用较少,一般使用LinkedBlockingQueue和Synchronous。

    线程池的排队策略与BlockingQueue有关。

6、threadFactory:线程工厂,主要用来创建线程;

7、handler:表示当拒绝处理任务时的策略,有以下四种取值:

ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。 
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。 
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务 

 

参考博文:http://www.cnblogs.com/dolphin0520/p/3932921.html

以上是关于Java多线程小结的主要内容,如果未能解决你的问题,请参考以下文章

Java多线程小结

java多线程面试题小结

《java并发编程的艺术》学习小结

《java并发编程的艺术》学习小结

java concurrent包常用类小结

多线程小结