一、多线程

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

二、Thread类

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

 public class Thread implements Runnable {

     public Thread() {
//...
} public Thread(Runnable target) {
//...
} public static void sleep(long millis, int nanos)
throws InterruptedException {
//...
} public synchronized void start() {
//...
} public void run() {
//...
}
}

可以看到,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> {
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<String>{
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<String> task=new FutureTask<String>(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<V> {
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<String>{
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<String> res=pool.submit(new MyCallable());
//得到线程执行返回的结果
System.out.println(res.get());
//关闭线程池
pool.shutdown();
}
}

Java多线程之Thread、Runnable、Callable及线程池的更多相关文章

  1. JAVA多线程之UncaughtExceptionHandler——处理非正常的线程中止

    JAVA多线程之UncaughtExceptionHandler——处理非正常的线程中止 背景 当单线程的程序发生一个未捕获的异常时我们可以采用try....catch进行异常的捕获,但是在多线程环境 ...

  2. (一)java多线程之Thread

    本人邮箱: kco1989@qq.com 欢迎转载,转载请注明网址 http://blog.csdn.net/tianshi_kco github: https://github.com/kco198 ...

  3. java多线程之:创建开启一个线程的开销

    ---->关于时间,创建线程使用是直接向系统申请资源的,这里调用系统函数进行分配资源的话耗时不好说.---->关于资源,Java线程的线程栈所占用的内存是在Java堆外的,所以是不受jav ...

  4. Java多线程之Runnable与Thread

    Java多线程之Thread与Runnable 一.Thread VS Runnable 在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口:Thread类和 ...

  5. Java基础-进程与线程之Thread类详解

    Java基础-进程与线程之Thread类详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.进程与线程的区别 简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程 ...

  6. java多线程之wait和notify协作,生产者和消费者

    这篇直接贴代码了 package cn.javaBase.study_thread1; class Source { public static int num = 0; //假设这是馒头的数量 } ...

  7. JAVA多线程之wait/notify

    本文主要学习JAVA多线程中的 wait()方法 与 notify()/notifyAll()方法的用法. ①wait() 与 notify/notifyAll 方法必须在同步代码块中使用 ②wait ...

  8. JAVA多线程之volatile 与 synchronized 的比较

    一,volatile关键字的可见性 要想理解volatile关键字,得先了解下JAVA的内存模型,Java内存模型的抽象示意图如下: 从图中可以看出: ①每个线程都有一个自己的本地内存空间--线程栈空 ...

  9. java多线程之yield,join,wait,sleep的区别

    Java多线程之yield,join,wait,sleep的区别 Java多线程中,经常会遇到yield,join,wait和sleep方法.容易混淆他们的功能及作用.自己仔细研究了下,他们主要的区别 ...

随机推荐

  1. postgreysql

    基础 syntax * \help 生成所有的pg命令 * abort 终止事务/work * alter aggregate 修改聚合函数的定义 ALTER AGGREGATE name ( typ ...

  2. 裸奔着造房子——对政府禁止采购Win8系统的一些看法

    前段时间有消息称政府招标的项目将禁止使用Win8系统,原因是Win8系统的安全架构将有利于暴露敏感信息给微软,而微软的老子是美利坚,老子想要知道什么,儿子当然不敢不从.因此Win8也被打入冷宫,微软多 ...

  3. IT帮2019年2月线下活动【定义工作,解读自我】之站桩练习

    2019年2月IT帮线下活动[定义工作,解读自我] 昨天的活动收获很大,全面的总结周老师会另写一篇来帮助大家回顾.我想说一下其中最打动我的一句话:“只有你能决定你有多优秀!” “工作中把自己当成企业家 ...

  4. CLOUDSTACK FOR HYPER-V

    原文地址:http://zhu.vn/archives/1040 我这里是内网测试环境,宿主机为Server 2012R2 ,虚拟化技术为HYPER-V,域环境来的(不是域环境玩不了). 先给宿主机安 ...

  5. IOS开发学习笔记030-xib实现淘宝界面

    使用xib文件实现界面,然后通过模型更新数据. 1.使得控制器继承自UITableViewController 2.创建xib文件,实现界面如下:一个UIImageView,两个lable 3.新建一 ...

  6. ogre3D学习基础3 -- 粒子与表层脚本

    9.粒子脚本 粒子脚本允许你实例化地在你的脚本代码中定义粒子系统,而不必在源代码中进行设置,使得你做任何修改都能得到快速回应.脚本里定义的粒子系统被用作模板,并且多个实际的系统可以在运行时从这里被创建 ...

  7. android AsyncTask使用限制

    由于AsyncTask内部是使用线程池(ThreadPoolExecutor)来管理要处理的任务的,所以AsyncTask的弊端就非常明确了:要extcute的任务数量超过线程池最大容量时,必然会报错 ...

  8. Python flask几个小问题

    1.这句是个重定向,如果sse_id为空,定向到StudentScoreCenter()这个函数返回的uURL中(就是回到学生分数中心). 2.g是flask一个固定的用法,用来存登陆信息的,你可以简 ...

  9. BZOJ 2818: Gcd(欧拉函数)

    GCDDescription 给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的数对(x,y)有多少对. Input 一个整数N Output 如题 Sample Input 4 ...

  10. Rust学习资源和路线

    Rust学习资源和路线 来源 https://rust-lang-cn.org/article/23 学习资源 The Rust Programming Language 堪称Rust的"T ...