并发编程——关于任务的执行(Task Execution)

本文探讨了多线程套接字编程的不足,如线程创建销毁的高成本和内存消耗,并引入了Java的Executor框架和线程池作为解决方案。介绍了Executor接口的execute方法以及线程池的四种类型:newFixedThreadPool、newCachedThreadPool、newSingleThreadExecutor和newScheduledThreadPool。还讨论了线程池的生命周期管理,包括shutdown和shutdownNow方法。最后,提到了Callable和Future接口,用于处理带有返回结果的任务,并举例说明了它们的使用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.多线程套接字编程中的不足
记得之前做过学校的一个实验,是关于多线程套接字编程地,在那次实验中,我们采用了如下的代码:

ServerSocket server = new ServerSocket(80);
while(true){
    //新建线程
    new  Thread(xxx).start;
    }

在上方代码,我们为了提升服务器的效率,我们使用了多线程编程,但是同时,这个代码,他也是会无限制创建线程地,他的不足主要有:
1.线程每次创建和销毁的代价非常高;2.对内存的消耗很大,可运行的线程数量很可能多于处理器数量;3.稳定性,如果线程超过了当前虚拟机或者操作系统的限制,那很可能抛出异常。

针对这种代码,我们给出了更好的解决方案,就是使用线程池。

2.1关于Executor框架和线程池
Excetor是一个接口,它里面就是一个execute方法,参数是Runnable类型,作用就是执行这个实现了Runable接口的类的线程。很简单,但是为灵活且强大的线程池(异步执行框架)提供了基础。

关于线程池的使用:

类A {
    private static final Exceutor exex = Executors.newFixedThreadPool(100);

    public static void main(String[] args)throws IOException{
        ServerSocket socket = new ServerSocket(80);
        Runnable task = new B//某个实现了Runnable的类
        exec.execute(task);
    }
}

关于线程池的优势:1.可以宠用现有线程,而不用创建新线程,节省开销;2.可以限定线程池大小,创建足够多的线程让系统保持忙碌,却不会耗尽资源使任务失败。
类库提供了一些Executors静态工厂方法来创建一个线程池:
1.newFixedThreadPool。 创建一个固定长度的线程池
2.newCachedThreadPool。 创建一个可缓存的线程池,如果线程池的当前规模超过了处理需求时,那么将回收空闲的线程,而当需求增加时则可以添加新的线程,线程池的规模不存在任何限制。
3.newSingleThreadExecutor。这是一个单线程的线程池,他创建单个工作者线程来执行任务,如果这个线程异常结束,会创建另一个线程来代替。
4.newScheduledThreadPool。创建了一个固定长度的现车公尺,而且一延时或定时的方式来执行任务,类似Timer定时器。

newFixedThreadPool和newCachedThreadPool这两个工厂方法返回通用的ThreadPoolExecutor实例,可以直接用来构造专门用途的exxecutor

2.2线程池的生命周期
ExecutorService 拓展了Executor接口,新增了关于结束线程池生命的方法,就是说,我们可以用ExecutorService接口,就可以承接真是的线程池实例类了。
主要方法有shutdown()//正常、安全、缓慢关闭; 还有shutdownnow//强行快速关闭线程池

2.3线程池和携带结果的任务,Callable和Future
Runnable是一种有局限的抽象,run,它并不能返回一个值。所以我们有了Callable接口,他认为主入口点(call方法)将返回一个值,并可能抛出一个异常。
Future表示一个任务的生命周期,并提供方法来判断是否完成或者取消,获取任务结果,他隐含了一个含义,任务的生命周期只能前进,不能后退。他也是一个接口。
get方法取决于任务状态,如果任务还没完成就会阻塞。
关于Future和Callable的使用例子,使用Future等待图像下载:

class FutureRenderer {  
    private final ExecutorService executor = .;  

    void renderPage(CharSequence source) {  
        final List<ImageInfo> imageInfos = scanForImageInfo(source);  
        Callable<List<ImageData>> task = new Callable<List<ImageData>> () {  
            public List<ImageData> call() {  
                List<ImageData> result = new ArrayList<ImageData>();  
                for(ImageInfo imageInfo : imageInfos) {  
                    result.add(imageInfo.downloadImage());  
                }  
                return result;  
            }  
        };  

        Future<List<ImageData>> future = executor.submit(task);  
        renderText(source);  
        try{  
            List<ImageData> imageData = future.get();  
            for(ImageData data : imageData) {  
                rederImage(data);  
            }  
        } catch (InterruptedException e) {  
            //重新设置线程的中断状态  
            Thread.currentThread().interrupt();  
            //由于不需要结束,因此取消任务  
            future.cancel(true);  
        } catch (ExecutionException e) {  
            throw launderThrowable(e.getCause());  
        }  
    }  
}  

我们还可以通过Future的get方法来为任务设置时间限制:
V get (long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException 同上面的get功能一样,多了设置超时时间。参数timeout指定超时时间,uint指定时间的单位,在枚举类TimeUnit中有相关的定义。如果计算超时,将抛出TimeoutException

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值