java线程与线程池

Java通过Executors提供四种线程池,分别为:
newCachedThreadPool:可缓存线程池
newFixedThreadPool:定长线程池
newScheduledThreadPool:定长线程池,支持定时及周期性任务执行

newSingleThreadExecutor:单线程化的线程池

使用Executors哪里有风险?有什么风险?

Executors 返回线程池对象的弊端如下:

FixedThreadPool 和 SingleThreadExecutor : 允许请求的队列长度为 Integer.MAX_VALUE,可能堆积大量的请求,从而导致OOM。

CachedThreadPool 和 ScheduledThreadPool : 允许创建的线程数量为 Integer.MAX_VALUE ,可能会创建大量线程,从而导致OOM。

1.1 newCachedThreadPool:可缓存线程池,线程池是无限大的,当一个线程完成任务之后,这个线程可以接下来完成将要分配的任务,而不是创建一个新的线程.如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

public static void main(String[] args) {
		ExecutorService cachedThreadPool = Executors.newCachedThreadPool();//创建线程池
		for (int i = 0; i < 10; i++) {
			final int index = i;
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			cachedThreadPool.execute(new Runnable() {
				public void run() {
					System.out.println(Thread.currentThread().getName() + "-" + index);
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			});
		}
		cachedThreadPool.shutdown();//关闭线程池
	}

1.2 newFixedThreadPool :定长线程池,可控制线程最大并发数,超出的线程会在队列中等待;定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()(Java虚拟机的可用的处理器数量)

public static void main(String[] args) {
	ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);//创建线程池
		for (int i = 0; i < 15; i++) {
			final int index = i;
			fixedThreadPool.execute(new Runnable() {
				public void run() {
					try {
						System.out.println(Thread.currentThread().getName() + "-" + index);
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			});
		}
		fixedThreadPool.shutdown();//关闭线程池
	} 

 

1.3 ScheduledExecutorService :创建一个定长线程池,支持定时及周期性任务执行。

 

延迟执行示例代码如下:延迟3秒执行

public static void main(String[] args) {  
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);  
        for (int i = 0; i < 10; i++) { 
        	final int index = i;
            scheduledThreadPool.schedule(new Runnable() {  
                public void run() {  
                	System.out.println(Thread.currentThread().getName() + "-" + index); 
                }  
            }, 3, TimeUnit.SECONDS);  
        }  
    }

定期执行示例代码如下:延迟1秒后每3秒执行一次

public static void main(String[] args) {  
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);  
        for (int i = 0; i < 10; i++) { 
        	final int index = i;
            scheduledThreadPool.scheduleAtFixedRate(new Runnable() {  
                public void run() {  
                	System.out.println(Thread.currentThread().getName() + "-" + index); 
                }  
            }, 1, 3, TimeUnit.SECONDS);  
        }  
        
    }

定期执行示例代码如下:每天晚上8点执行一次

       public static void main(String[] args) {
		ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
		long oneDay = 24 * 60 * 60 * 1000;
		long initDelay = getTimeMillis("20:00:00") - System.currentTimeMillis();
		initDelay = initDelay > 0 ? initDelay : oneDay + initDelay;
		for (int i = 0; i < 10; i++) {
			final int index = i;
			scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
				public void run() {
					System.out.println(Thread.currentThread().getName() + "-" + index);
				}
			}, initDelay, oneDay, TimeUnit.MILLISECONDS);
		}
		
	} 
	/** 
	 * 获取指定时间对应的毫秒数 
	 * @param time "HH:mm:ss" 
	 * @return 
	 */  
	private static long getTimeMillis(String time) {  
	    try {  
	        DateFormat dateFormat = new SimpleDateFormat("yy-MM-dd HH:mm:ss");  
	        DateFormat dayFormat = new SimpleDateFormat("yy-MM-dd");  
	        Date curDate = dateFormat.parse(dayFormat.format(new Date()) + " " + time);  
	        return curDate.getTime();  
	    } catch (ParseException e) {  
	        e.printStackTrace();  
	    }  
	    return 0;  
	}

1.4 newSingleThreadExecutor: 单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行

示例代码如下:

public static void main(String[] args) {
		ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
		for (int i = 0; i < 10; i++) {
			final int index = i;
			singleThreadExecutor.execute(new Runnable() {
				public void run() {
					try {
						System.out.println(Thread.currentThread().getName() + "-" + index);
						Thread.sleep(2000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			});
		}
		singleThreadExecutor.shutdown();
	}

2.1 线程池参数介绍

参数介绍:

corePoolSize:核心线程数,指保留的线程池大小(不超过maximumPoolSize值时,线程池中最多有corePoolSize 个线程工作)。 
maximumPoolSize:指的是线程池的最大大小(线程池中最大有corePoolSize 个线程可运行)。 
keepAliveTime 指的是空闲线程结束的超时时间(当一个线程不工作时,过keepAliveTime 长时间将停止该线程)。 
unit 是一个枚举,表示 keepAliveTime 的单位(有NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS,7个可选值)。 
workQueue :表示存放任务的队列(存放需要被线程池执行的线程队列)。 

handler:拒绝策略(添加任务失败后如何处理该任务).

 

当一个任务通过execute(Runnable)方法欲添加到线程池时:

    1.如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。

    2.如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。

    3.如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。

   4.如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。也就是:处理任务的优先级为:核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。  

     当线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止。这样,线程池可以动态的调整池中的线程数。

2.2 存放任务队列 BlockingQueue

 

常用的几种BlockingQueue:

  • ArrayBlockingQueue(int i):规定大小的BlockingQueue,其构造必须指定大小。其所含的对象是FIFO顺序排序的。

  • LinkedBlockingQueue()或者(int i):大小不固定的BlockingQueue,若其构造时指定大小,生成的BlockingQueue有大小限制,不指定大小,其大小有Integer.MAX_VALUE来决定。其所含的对象是FIFO顺序排序的。

  • PriorityBlockingQueue()或者(int i):类似于LinkedBlockingQueue,但是其所含对象的排序不是FIFO,而是依据对象的自然顺序或者构造函数的Comparator决定。

  • SynchronizedQueue():特殊的BlockingQueue,对其的操作必须是放和取交替完成。

2.3 handler:拒绝策略

 

RejectedExecutionHandler提供了四种方式来处理任务拒绝策略

  1、直接丢弃(DiscardPolicy)

  2、丢弃队列中最老的任务(DiscardOldestPolicy)。

  3、抛异常(AbortPolicy)

  4、将任务分给调用线程来执行(CallerRunsPolicy)。

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中,线程是程序执行的基本单元,用于并发执行任务。每个线程都有自己的生命周期,包括创建、运行、阻塞和终止。线程的创建可以通过继承Thread类或实现Runnable接口来实现。 线程池则是Java中一种高效的线程管理机制,它预先创建一定数量的工作线程,并在需要执行任务时从线程池中获取线程进行处理,当任务完成后,线程会返回到线程池等待下一次调度,而不是立即结束。这样可以避免频繁地创建和销毁线程带来的开销,提高系统的性能和资源利用率。 以下是Java线程线程池的一些关键点: 1. **线程创建**: - **继承Thread类**:创建自定义线程类并重写run()方法。 - **实现Runnable接口**:创建Runnable接口的实现类,提供run()方法,然后用Thread构造函数创建Thread实例。 2. **线程状态**: - 新建(New):线程对象被创建但还未启动。 - 运行(Runnable):线程正在执行run()方法。 - 阻塞(Blocked):线程因某个条件而暂停,如I/O操作等待数据。 - 等待(Waiting):线程在调用wait()方法后,进入等待状态,直到被其他线程唤醒。 - 守护(Terminated):非守护线程完成或主线程结束,守护线程自动退出。 3. **线程池组件**: - ExecutorService:线程池的核心接口,提供了提交任务和控制线程的方法。 - ThreadPoolExecutor:实现了ExecutorService,包含核心线程数、最大线程数、任务队列等配置。 - ScheduledThreadPoolExecutor:支持定时和周期性任务。 4. **线程池的优势**: - **资源复用**:减少线程创建和销毁的开销。 - **线程管理和调度**:灵活设置线程数量、线程优先级和任务执行策略。 - **避免死锁**:由于任务有顺序地等待特定资源,减少了死锁的可能性。 - **可扩展性**:随着任务增加,线程池可以根据需要动态调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值