Java-多线程-线程池

在JDK5以后,对于线程池的功能需求一般情况下都可以通过java.util.concurrent包里提供的API满足。其中可以通过java.util.concurrent.ExecutorService接口、子接口、及其实现类来实现一般情况下的线程池功能;通过java.util.concurrent.SchduledExecutorService接口、子接口、及其实现类来实现具有时间安排的线程池功能。但在学习线程池之前,有必要先了解java.util.concurrent.Executor接口的内容。

Executor

package java.util.concurrent;

public interface Executor{

    void execute(Runnable command);

}

作用:将Runnable的指定与实际如何执行分离。

Demon

//Executor使用举例
import static java.lang.System.in;
import static java.lang.System.out;
import java.util.concurrent.Executor;
import java.lang.Runnable;
//异步的执行者
class SynchronizedExecutor implements Executor{
	public void execute(Runnable command){
		new Thread(command).start();
	}
}
//同步的执行者
class LocalExecutor implements Executor{
	public void execute(Runnable command){
		command.run();
	}
}
public class Temp {
    public static void main(String... args){
		Executor synchronizedExecutor = new SynchronizedExecutor();
		Executor localExecutor = new LocalExecutor();
		synchronizedExecutor.execute(()->{
			int n=30;
			while(n-->0)
				out.println("synchronized msg");
		});
		localExecutor.execute(()->{
			int n=20;
			while(n-->0)
				out.println("local msg");
		});
		out.println("flag,这句话一定出现在所有的local msg下面");
    }
}

 ExecutorService

package java.util.concurrent;
public interface ExecutorService extends Executor{
...
}

作用:用于满足线程池这里服务的行为需求。

用法:

(1)抽象类AbstractExecutorService实现了该接口,并且其子类java.util.concurrent.ThreadPoolExecutor提供有多种不同的构造函数,可以满足一般情况下创建线程池的需求。所以创建一个线程池的方法之一就是生成一个ThreadPoolExecutor对象,并通过其构造函数来指定该线程池的各个参数。

//构造函数参数详情,可以参考JDK开发文档

(2)最简洁的方法是,使用java.util.concurrent.Executors所提供的几个静态方法,通过调用它们可以返回操作了ExecutorService接口的对象,继而可以通过该对象调用ExecutorService所约定的方法。

Executors.newCachedThreadPool()        //无限线程池,具有自动线程回收
Executors.newFixedThreadPool(int)      //固定数量的线程池
Executors.newSingleThreadExecutor()    //单个后台线程

Demo

//ExecutorService使用举例
import static java.lang.System.in;
import static java.lang.System.out;
import java.util.concurrent.*;
import java.lang.Runnable;
import java.io.*;
import java.net.URL;
class PagesDownload {
	URL[] urls;
	ExecutorService executorService;
	public PagesDownload(URL[] tu, ExecutorService es){
		this.urls = tu;
		this.executorService = es;
	}
	public void download(){
		if(null == urls || null == executorService) return;
		for(int i=0; i<urls.length; i++){
			URL tempURL = urls[i];
			String fileName = ""+i+".html";
			//executorService.execute(()->{
			executorService.submit(()->{
				try{
					PagesDownload.dataCopy(tempURL.openStream(), new FileOutputStream(fileName));
				}catch(IOException e){
					throw new RuntimeException(e);
				}
			});
		}
	}
	private static void dataCopy(InputStream src, OutputStream dest)throws IOException{
		try(InputStream input = src; OutputStream output = dest){
			byte[] bytes = new byte[2048];
			int len;
			while((len = input.read(bytes))!=-1){
				output.write(bytes, 0, len);
			}
		}
	}
}
public class Temp {
    public static void main(String... args) throws Exception{
		//Demo中,你可以指定自己的路径及文件
		URL[] urls = {new URL("file:///D:/TestArea/index.html"), new URL("http://www.baidu.com")};
		ExecutorService es = Executors.newCachedThreadPool();
		new PagesDownload(urls, es).download();
		es.shutdown();
    }
}

 

ScheduledExecutorSerivce

package java.util.concurrent;
public interface ScheduledExecutorService extends ExecutorService{
...
}

作用:用于提供具有周期线程性质的线程池服务。

用法:

(1)java.util.concurrent.ScheduledThreadPoolExecutor是继承了ThreadPoolExecutor且操作了ScheduledExecutorService接口的一个类,具有线程池与排程功能。可以通过创建该类的对象来构建周期线程池服务。在其构造函数的形参上可以指定相关参数,以进行更细致的线程池服务创建。

//构造函数参数详情,可以参考JDK开发文档

(2)同样的,java.util.concurrent.Executors也为开发者提供了便捷的静态方法,用于直接创建并返回一个操作了ScheduledExecutorService接口的对象,开发者可以通过它完成具有周期性质的线程池服务的部署。

newScheduledThreadPool(int corePoolSize) //创建一个线程池,可以调度命令在给定的延迟之后运行,或定期执行。  
newSingleThreadScheduledExecutor() //创建一个单线程执行器,可以调度命令在给定的延迟之后运行,或定期执行。

Demo

//ScheduledExecutorService使用举例
import java.util.concurrent.*;
import static java.lang.System.out;
public class Temp{
    public static void main(String... args){
        ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
        service.scheduleWithFixedDelay(()->{
            out.println(new java.util.Date());
            try{
                Thread.sleep(2000); //假定这里工作2秒
            }catch(InterruptedException e){
                throw new RuntimeException(e);
            }
        }, 2000, 1000, TimeUnit.MILLISECONDS);
		
	}
}

 

*ps:java.util.concurrent.Callable接口与java.util.concurrent.Future接口

在使用ExecutorService的submit()、invokeAll()、invokeAny()等方法时,可以发现,其重载函数支持传递Callable的操作对象,所有这里简单介绍一下Callable与Runnable的区别。

package java.util.concurrent;
public interface Callable<V>{
    V call() throws Exception;
}

Callable与Runnable类似,都可以定义执行流程,但Runnable的run()方法无法返回值,且不能抛出受检异常,而Callable恰恰是对其进行了补充,Callable的call()方法不仅可以有返回值,而且还可以抛出受检异常。至于如何获取Callable的值,这需要通过与Future接口搭配使用才能做到。

Future接口被定义为对未来情况的引用,其定义有如下方法:

boolean cancel(boolean mayInterruptIfRunning) //尝试取消执行此任务。  
V get() //等待计算完成,然后检索其结果。  
V get(long timeout, TimeUnit unit) //等待给定时间,然后获取其结果。  
boolean isCancelled() //如果此任务在正常完成之前被取消,则返回 true 。  
boolean isDone() //返回 true如果任务已完成。 

java.util.concurrent.FutureTask<V>的构造函数可以接受操作了Callable接口的对象,而其操作的接口RunnableFuture继承了Runnable与Future,所以其对象可以被用来构造Thread,从而实现异步执行指定过程的同时,异步地获取指定过程的处理结果。如下面的Demo:

import java.util.concurrent.*;
import static java.lang.System.*;
public class Temp{
    public static void main(String... args) throws Exception{
        FutureTask<String> targetFuture = new FutureTask<String>(()->{int i=10; while(i-->0) Thread.sleep(500); return "脑力不足请求支援";});
		out.println("101区脑细胞负责学习");
		new Thread(targetFuture).start();
		while(!targetFuture.isDone()){
			out.println("102区脑细胞负责打游戏");
		}
		out.println("101区脑细胞的学习结果:"+targetFuture.get());//直接调用get()会被阻塞
	}
}

 

 

 

 如有不当,望留言指明,非常感谢!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值