使用多线程的目的
一、在多核的cup处理器中,可以合理的利用资源,将任务分解开来,减缓单个cup的压力。
二、在单核cpu处理器中,可以在一些不用cup的任务下,释放cup,让cup执行其他任务,比如IO操作阻塞的时候,是不需要CPU参与的。
创建多线程的方式和区别
一、创建多线程的方式
继承 Thread 类、实现 Runnable 接口、实现 Callable 接口、线程池
二、区别
1、继承 Thread 类:执行run方法体,扩展性不好;(java是单继承)对对应类资源的扩展性差
2、实现 Runnable 接口:执行run方法体,不可以抛出异常,无返回值,继承接口,扩展性好;(java多实现)对对应类资源扩展性较好
3、实现 Callable 接口:需要FutureTask的帮助,执行call方法体,可以抛出异常,有返回值,编码很麻烦。
注:通过FutureTask的get方法获取返回值的时候,这时候调用线程是被阻塞住了,直到通过get获取到call方法的返回值。
线程池:用于重复创建线程时使用,降低线程创建和销毁时造成的消耗,对线程进行统一管理(分配、调优、监控)
对于多线程的简单应用可以通过多线程的简单应用了解一下
4、线程池:对线程的统一管理调度使用;
ThreadPoolExecutor的参数解释:corePoolSize,即核心线程数
maximumPoolSize,即最大线程数
(若是需要让核心线程也遵循这个需要进行设置allowCoreThreadTimeOut)
keepAliveTime,非核心线程的空闲存活时间
unit,非核心线程的空闲存活时间类型
workQueue,工作队列
threadFactory,创建线程的工厂
handler,拒绝策略
线程池的运行原理,通过 excute方法或者commit方法提交一个任务,线程池会先new出核心线程进行执行,若核心线程数使用完了,会将任务放入队列,等线程空闲时再执行任务,若队列满了,就会创建非核心线程执行任务,若非核心线程数也达到最大时,就是执行拒绝策略(默认报出异常,也可自定义处理)。
线程start()和run()区别
start()
public synchronized void start() {
if (started)
throw new IllegalThreadStateException();
group.add(this);
started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
以上时start()源码,start()方法是被synchronized修饰的方法,可以保证线程安全,只能调用一次start()方法启动线程,不可多次调用。
private native void start0();
start0()方法使用native修饰,所以运行在本地方法栈中,通过c++实现的,里面才是对线程创建和启动,再通过native interface饭回来调用run()方法。
如果直接调用run()方法,只不过是运行在当前线程的普通方法,并不是运行在new出来的新的线程中。
中断线程的方式
Thread.stop方法
:突然关闭停止了一个正在运行的线程,可能会产生不可预料的结果,这种方法是不安全也是不受提倡的。
Thread.interrupt()方法
: 作用是中断线程。将会设置该线程的中断状态位,即设置为true,中断的结果线程是死亡、还是等待新的任务或是继续运行至下一步,就取决于这个程序本身。线程会不时地检测这个中断标示位,以判断线程是否应该被中断(中断标示值是否为true)。interrupt()方法只是改变中断状态,不会中断一个正在运行的线程。需要用户自己去监视线程的状态为并做处理.
Thread.interrupted()
:测试当前线程是否已经中断(静态方法)。如果连续调用该方法,则第二次调用将返回false。在api文档中说明interrupted()方法具有清除状态的功能。执行后具有将状态标识清除为false的功能。
thread.isInterrupted()
:测试线程是否已经中断,但是不能清除状态标识。