博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java多线程之Thread、Runnable、Callable及线程池
阅读量:7142 次
发布时间:2019-06-29

本文共 4178 字,大约阅读时间需要 13 分钟。

一、多线程

      线程是指进程中的一个执行流程,一个进程中可以有多个线程。如java.exe进程中可以运行很多线程。进程是运行中的程序,是内存等资源的集合,线程是属于某个进程的,进程中的多个线程共享进程中的内存。线程之间的并发执行是线程轮流占用资源执行的结果,给人一种“同时”执行的感觉。在Java中多线程的编程有很多方法来实现,这里从Thread类、Runnable与Callable接口以及线程池等几个方式来探讨。

二、Thread类

     以下是Thread类的部分源代码:

1 public class Thread implements Runnable { 2      3     public Thread() { 4         //... 5     } 6      7     public Thread(Runnable target) { 8        //... 9     }10     11     public static void sleep(long millis, int nanos) 12     throws InterruptedException {13     //...14     }15 16     public synchronized void start() {17        //...18     }19 20     public void run() {21     //...22     }23 }

      可以看到,Thread类实际上是实现了Runnable接口的,重写了Runnable接口中的run()方法;Thread的对象可以通过Runnable的对象来构造,此时如果调用了run()方法,那么这个run()方法是Runnable对象中的run()方法;调用start()方法会启动线程,并将引发调用run()方法,实现并行运行;sleep()使当前的线程暂停一段时间执行,此时当前线程的还占用着资源,并不会释放资源,等到时间到了就会接着继续执行。

      一个Thread的简单示例,以帮助理解:

class TestThread extends Thread{public void run(){//...}}public class Test{public static void main(String []args){Thread t=new TestThread();t.start();}}

三、Runnable接口与Callable接口

     还是从Runnable与Callable的源码开始,

public interface Runnable {    public abstract void run();}public interface Callable
{ V call() throws Exception;}

    Runnable封装一个异步运行的任务,可以把它想象成一个没有参数和返回值的异步方法,而run()方法提供所要执行任务的指令。Callable与Runnable类似,不同的是Callable接口是一个参数化的类型,而且有返回值,返回值的类型是参数的类型,如Callable<Integer>是最终返回一个Integer对象的异步任务;Callable提供一个返回参数类型的call方法,和run()的作用类似。

    Runnable与Callable接口的应用示例:

/** * Runnable接口 * */class TestRunnable implements Runnable{    public void run() {        //...    }}public class Test {    public static void main(String[] args){        Thread t=new Thread(new TestRunnable());        t.start();    }}/** * Callable接口 * */class TestCallable implements Callable
{ public String call() throws Exception { String s="good"; return s; }}public class Test { public static void main(String[] args) throws Exception{ /** * FutureTask实现了Future(用于保存异步计算的结果)和Runnable的接口,可将Callable转换成Future和Runnable */ FutureTask
task=new FutureTask
(new TestCallable()); Thread t=new Thread(task); t.start(); //取得Callable异步线程的返回值 System.out.println(task.get()); }}

四、线程池

     构造一个新的线程是有一定代价的,会涉及到与操作系统的交互。如果程序中创建了大量的生命周期很短的线程,应该使用线程池(thread pool)。一个线程池中包含一些准备运行的空闲线程。将Runnable对象交给线程池,就会有一个线程调用run()方法,当run()方法退出时,线程不会死亡,而是在线程池中准备为下一个请求提供服务。

     使用线程池还会减少并发线程的数量。创建大量的线程会大大降低性能甚至是虚拟机崩溃,所有最好是使线程的数目是“固定”的,以限制并发线程的总数。

     线程池的创建是使用执行器(Executors)的静态工厂方法,如下:

     1、newCachedThreadPool 构建一个线程池,对于每个任务,如果有空闲线程可用,则立即让它执行,如果没有空闲的线程,则创建一个线程,空闲线程会被保留60秒;

     2、newFixedThreadpool 构建一个具有固定大小的线程池。如果提交的任务多于空闲的线程数,那么把到不到服务的任务放置到队列中,其它任务完成后再运行它们;

     3、newSingleThreadExecutor 是一个退化了大小为1的线程池,由一个线程提交任务,一个接一个。

     这三个方法都返回了实现了ExecutorService接口的ThreadPoolExecutor类的对象。使用submit方法将Runnable或Callable对象提交给ExecutorService,在调用了submit时会得到一个Future对象,可用来查询任务的状态,future的接口如下:

public interface Future
{ boolean cancel(boolean mayInterruptIfRunning); boolean isCancelled(); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;}

cancel方法用来取消运行的,如果还没开始运行,则它被取消且不再开始;如果正在运行中,则若mayInterrupt参数为true,它就被中断;

isDone判断任务是否完成,若任务在运行中,isDone返回fasle,如果完成了,则返回true;

不带参数的get方法调用时被阻塞,直到计算完成;如果在计算完成之前,第二个get的调用超时,就会抛出异常;如果该线程被中断,那么两个get都会抛出异常。

     线程池的执行流程如下:

     1、调用Executors类中的静态方法创建线程池;

     2、使用submit提交Ruunable或Callable对象;

     3、保存返回的Future对象;

     4、没有任务提交时,调用shutdown来关闭线程池。

  线程池的示例如下:

/** * 线程池 * */class MyCallable implements Callable
{ public String call() throws Exception { String s="good"; return s; }}public class Test { public static void main(String[] args) throws Exception{ //创建大小固定为3的线程池 ExecutorService pool=Executors.newFixedThreadPool(3); //提交一个Callable任务到线程池,并把结果保存到future对象中 Future
res=pool.submit(new MyCallable()); //得到线程执行返回的结果 System.out.println(res.get()); //关闭线程池 pool.shutdown(); }}

转载于:https://www.cnblogs.com/harderman-mapleleaves/p/4514561.html

你可能感兴趣的文章
"不能连接到服务器"时收到错误消息 Lync 在线用户尝试登录到移动设备上的 Lync 2010 移动客户端...
查看>>
U盘安装redhat6.3
查看>>
十步完全理解SQL
查看>>
${!i}
查看>>
用Cacls命令修改文件访问控制权限
查看>>
linux 共享内存操作
查看>>
Ext.data库中几个常用类的原理及其使用
查看>>
细说C++覆盖方法和重载方法
查看>>
管理重做日志文件
查看>>
jee容器中运行php
查看>>
Go语言之切片Slice练习
查看>>
使用命令esxcli升级系统,从ESXi5.1升级到ESXi5.1b
查看>>
CPP 模板测试
查看>>
Exchange2003-2010迁移系列之十二,Exchange组织及服务器配置
查看>>
chown命令
查看>>
Apache如何开启Rewrite功能
查看>>
思科网络路由知识点整理五
查看>>
使用cronolog分割apache日志,使用awstats分析按日期生成的apache日志
查看>>
Objective-C ---UIButton (梳理整理)
查看>>
>不乱码思维流程
查看>>