一、定义一个线程(Defining a Thread)有两种方法
继承Thread接口
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("我在运行");
}
}
实现java.lang.Runnable接口
public class MyThread implements Runnable {
@Override
public void run() {
System.out.println("我在运行");
}
}
2、启动线程
MyThread mythread = new MyThread();
mythread.start();
3、线程的5种状态
新生状态(New): 当一个线程的实例被创建即使用new关键字和Thread类或其子类创建一个线程对象后,此时该线程处于新生(new)状态,处于新生状态的线程有自己的内存空间,但该线程并没有运行,此时线程还不是活着的(not alive);
就绪状态(Runnable): 通过调用线程实例的start()方法来启动线程使线程进入就绪状态(runnable);处于就绪状态的线程已经具备了运行条件,但还没有被分配到CPU即不一定会被立即执行,此时处于线程就绪队列,等待系统为其分配CPCU,等待状态并不是执行状态; 此时线程是活着的(alive);
运行状态(Running): 一旦获取CPU(被JVM选中),线程就进入运行(running)状态,线程的run()方法才开始被执行;在运行状态的线程执行自己的run()方法中的操作,直到调用其他的方法而终止、或者等待某种资源而阻塞、或者完成任务而死亡;如果在给定的时间片内没有执行结束,就会被系统给换下来回到线程的等待状态;此时线程是活着的(alive);
阻塞状态(Blocked):通过调用join()、sleep()、wait()或者资源被暂用使线程处于阻塞(blocked)状态;处于Blocking状态的线程仍然是活着的(alive)
死亡状态(Dead):当一个线程的run()方法运行完毕或被中断或被异常退出,该线程到达死亡(dead)状态。此时可能仍然存在一个该Thread的实例对象,当该Thready已经不可能在被作为一个可被独立执行的线程对待了,线程的独立的call stack已经被dissolved。一旦某一线程进入Dead状态,他就再也不能进入一个独立线程的生命周期了。对于一个处于Dead状态的线程调用start()方法,会出现一个运行期(runtime exception)的异常;处于Dead状态的线程不是活着的(not alive)。
4、线程池
首先整理下线程池的相关接口
Executor:顶级接口,只定义了一个void execute(Runnable command)方法
ExecutorService:该接口继承了Executor接口并声明了
shutdown: 关闭线程池,正在运行和等待运行的任务无法interrupt,仍会运行只有尚未运行的会被打断。
shutdownNow: 关闭线程池,尝试关闭所有任务,并返回尚未执行的task的list
isShutdown: 判断线程池是否被关闭(关闭:true)
submit: 内部调用的也是execute(),用来向线程池提交任务的,通过Future可以返回任务执行的结果
invokeAll(Collection<? extends Callable<T>> tasks): 批量提交任务
invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit): 批量提交任务,超出timeout时间范围未执行的任务会被取消
submit和execute的区别:
1、submit可以返回任务运行的结果,execute不可以
2、submit如果不调用返回的Future对象的get方法不会抛出线程中的异常
invokeAll用法
public class Main {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newSingleThreadExecutor();
List<MyCallable> callables = new ArrayList<>();
for(int i = 1; i <= 5; i++) {
callables.add(new MyCallable(10,i));
}
try {
List<Future<Integer>> futures = threadPool.invokeAll(callables, 10, TimeUnit.SECONDS);
System.out.println("运行结束");
for (int i = 0; i < futures.size(); i++) {
System.out.println(futures.get(i).get());
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
threadPool.shutdownNow();
}
}
}
class MyCallable implements Callable<Integer>{
private int price;
private int num;
public MyCallable(int price, int num){
super();
this.price = price;
this.num = num;
}
@Override
public Integer call() throws Exception {
Thread.sleep(3000);
System.out.println("用时3s,结果为:"+price*num);
return price*num;
}
}
运行结果:
用时3s,结果为:10
用时3s,结果为:20
用时3s,结果为:30
运行结束
shutdown和shutdownNow实例
shutdown()方法:
public static void main(String[] args){
ExecutorService threadPool = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
int a = i;
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(a);
}
});
}
threadPool.shutdown();
}
结果:打印0-9
shutdownNow()方法:
public static void main(String[] args){
ExecutorService threadPool = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
int a = i;
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(a);
}
});
}
List<Runnable> runnables = threadPool.shutdownNow();
System.out.println(runnables);
}
结果:打印0以及9个未执行的任务:
[Main$1@6e0be858, Main$1@61bbe9ba, Main$1@610455d6, Main$1@511d50c0, Main$1@60e53b93, Main$1@5e2de80c, Main$1@1d44bcfa, Main$1@266474c2, Main$1@6f94fa3e]
创建线程池的集中方法:
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务
ExecutorService singlePool = Executors.newSingleThreadExecutor();
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
ExecutorService fixedPool = Executors.newFixedThreadPool(5);
创建一个定长线程池,支持定时及周期性任务执行。
ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(5);
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
ExecutorService cachedPool = Executors.newCachedThreadPool();
singlePool fixedPool cachedPool 用下面形式创建
singlePool.execute(new Runnable() {
@Override
public void run() {
throw new NullPointerException();
// System.out.println(1);
}
});
推迟3秒调度
scheduledPool.schedule(new Runnable() {
public void run() {
System.out.println("delay 3 seconds");
}
}, 3, TimeUnit.SECONDS);
首次运行推迟3秒,之后每1秒运行一次
scheduleAtFixedRate()固定时间调度一次
scheduleWithFixedDelay()运行时间+固定时间调度一次