第一部分 多线程
1.1 多线程介绍:
进程:进程指正在运行的程序。确切的来说,当一个程序进入内存运行,即变为一个进程,进程是处于运行过程中的程序,并且具有一定的独立功能;
线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个程序运行后至少有一个线程, 一个进程中可以包含多个线程;
1.2 Thread类:
构造方法:
Thread():分配新的Thread对象;
Thread(String name):分配新的Thread对象,将指定的name作为其线程名称;
常用方法:
void start():使该线程开始执行;java虚拟机调用该线程的run方法;
void run():线程要执行的操作;
static void sleep(long millis):在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)
1.3 创建线程方式-继承Thread类
测试类:
public static void main(String[] args) {
//创建自定义线程对象
MyThread myThread = new MyThread("新的线程");
//开启新线程
myThread.start();
for (int i = 0; i < 100; i++) {
System.out.println("main线程正在运行"+ i);
}
}
自定义Thread类:
public class MyThread extends Thread {
//定义指定线程名称的构造方法
public MyThread(String name) {
//调用父类的String参数的构造方法,指定线程的名称
super(name);
}
@Override
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println(getName() + "正在执行"+ i);
}
}
}
1.4 创建线程方式-实现Runnable接口
自定义线程执行任务类:
public class MyRunnable implements Runnable {
@Override
public void run(){
for (int i = 0; i < 100 ; i++) {
System.out.println("自定义线程正在执行"+i);
}
}
}
测试类:
public class test {
public static void main(String[] args) {
//创建线程目标执行类对象
MyRunnable runn = new MyRunnable();
//将Runnable接口的子类对象作为参数传递给Thread类的构造函数
Thread thread = new Thread(runn);
Thread thread1 = new Thread(runn);
//开启线程
thread.start();
thread1.start();
for (int i = 0; i < 100; i++) {
System.out.println("main线程正在运行"+i);
}
}
}
1.5两种创建线程方式的区别:
实现Runnable接口,避免了继承Thread类的单继承局限性。覆盖Runnable接口中的run方法,将线程任务代码定义到run中;
实现Runnable接口的方式,更加的符合面向对象,线程分为两部分,一部分线程对象,一部分线程任务。继承Thread类,线程对象和线程任务耦合在一起。一旦创建Thread类的子类对象,既是线程对象,有又有线程任务。实现runnable接口,将线程任务单独分离出来封装成对象,类型就是Runnable接口类型。Runnable接口对线程对象和线程任务进行解耦
第二部分 线程池
线程池能够复用线程,减少线程的创建,销毁,恢复等状态切换的开销,提高程序的性能。一个线程池管理了一组工作线程,同时它还包括了一个用于放置等待执行的任务的队列;
2.1 ExecutorService 线程池
2.1.1 ExecutorService的创建
创建一个什么样的ExecutorService的实例(即线程池)需要各部根据具体的应用场景而定,java提供了Executors工厂类,可以很方便的创建各种类型的ExecutorService线程池,Executors可以创建下面四类线程池:
- newCachedThreadPool :创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程
- newFixedThreadPool :创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
- newScheduledThreadPool:创建一个定长线程池,支持定时或周期性的执行任务;
- newSingleThreadExecutor :创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO,LIFO,优先级)执行;
备注:Executors只是一个工厂类,它所有的方法返回的都是ThreadPoolExecutor、ScheduledThreadPoolExecutor这两个类的实例
2.1.2 ExecutorService的使用
public static void main(String[] args) {
//定义了包含10线程的线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println("task is doing");
}
});
executorService.shutdown();
}
2.1.3 ExecutorService的执行
ExecutorService有以下几个执行方法
- execute(Runnable)
- submit(Runnable)
- submit(Callable)
- invokeAny(...)
- invokeAll(...)
2.1.3.1 execute(Runnable)
这个方法接收一个Runnable实例,并且异步的执行:
public static void main(String[] args) {
//定义了包含10线程的线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println("task is doing");
}
});
System.out.println("other work is doing");
executorService.shutdown();
}
执行结果:
other work is doing
task is doing
缺点:没法获取task的执行结果
2.1.3.2 submit(Runnable)
public static void main(String[] args) throws Exception{
ExecutorService executorService = Executors.newFixedThreadPool(10);
Future future = executorService.submit(new Runnable() {
@Override
public void run() {
System.out.println("task is doing");
}
});
System.out.println("other work is doing");
executorService.shutdown();
//如果任务执行完成,future.get()方法会返回一个null,future.get()方法会产生阻塞
future.get();
System.out.println(future.get());
System.out.println("task is finish");
}
执行结果:
other work is doing
task is doing
null
task is finish
2.1.3.3 submit(Callable)
submit(Callable)和submit(Runnable)类似,也会返回一个Future对象,但是除此之外,submit(Callable)可以返回任务的执行结果
public static void main(String[] args) throws Exception{
ExecutorService executorService = Executors.newFixedThreadPool(10);
Future future = executorService.submit(new Callable<Object>() {
public Object call() throws Exception {
System.out.println("task is doing");
return "Callable Result";
}
});
System.out.println("other work is doing");
executorService.shutdown();
//如果任务执行完成,future.get()方法会返回一个null,future.get()方法会产生阻塞
future.get();
System.out.println("task is finish");
System.out.println(future.get());
}
执行结果:
other work is doing
task is doing
task is finish
Callable Result
多线程执行:
public static void main(String[] args) throws Exception{
ExecutorService executorService = Executors.newFixedThreadPool(5);
List<Future> futures = new ArrayList<>();
int cnt=0;
for (int i = 0; i < 5; i++) {
futures.add(executorService.submit(new Callable<Object>() {
public Object call() throws Exception {
System.out.println(Thread.currentThread().getName());
return Thread.currentThread().getName() + " callable Result";
}
}));
}
System.out.println("other work is doing");
//如果任务执行完成,future.get()方法会返回一个null,future.get()方法会产生阻塞
for(Future future : futures){
System.out.println(future.get());
}
System.out.println("task is finish");
executorService.shutdown();
}
执行结果:
pool-1-thread-1
other work is doing
pool-1-thread-2
pool-1-thread-4
pool-1-thread-1 callable Result
pool-1-thread-2 callable Result
pool-1-thread-5
pool-1-thread-3
pool-1-thread-3 callable Result
pool-1-thread-4 callable Result
pool-1-thread-5 callable Result
task is finish
如果任务执行完成,future.get()方法会返回Callable任务的执行结果。注意,future.get()方法会产生阻塞
2.1.3.4 invokeAny(…)
invokeAny(...)方法接收的是一个Callable的集合,执行这个方法不会返回Future,但是会返回所有Callable任务中其中一个任务的执行结果。这个方法也无法保证返回的是哪个任务的执行结果,反正是其中的某一个
机制:如果 集合中的某个task,完成了(或者抛出异常),那么集合中剩余的task将全部会被取消,不会得到执行
public static void main(String[] args) throws Exception{
ExecutorService executorService = Executors.newSingleThreadExecutor();
Set<Callable<String>> callables = new HashSet<Callable<String>>();
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 1";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 2";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 3";
}
});
String result = executorService.invokeAny(callables);
System.out.println("result = " + result);
executorService.shutdown();
}
执行结果:
result = Task 2 或者 result = Task 1 或者 result = Task 3
2.1.3.4 invokeAll(…)
方法invokeAll会调用存在于参数集合中的所有Callable对象,并且返回一个包含Future对象的集合,你可以通过这个返回的集合管理每个Callable的执行结果;
需要注意的是,任务有可能因为异常而导致运行结束,所以它可能并不是真的成功运行了。但是我们没有办法通过 Future 对象来了解到这個差异
public static void main(String[] args) throws Exception{
ExecutorService executorService = Executors.newSingleThreadExecutor();
Set<Callable<String>> callables = new HashSet<Callable<String>>();
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 1";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 2";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 3";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 4";
}
});
List<Future<String>> futures = executorService.invokeAll(callables);
System.out.println("other work is doing");
for(Future<String> future :futures ){
System.out.println("result = " + future.get());
}
System.out.println("task is finish");
executorService.shutdown();
}
执行结果:
other work is doing
result = Task 2
result = Task 4
result = Task 1
result = Task 3
task is finish
2.1.4 ExecutorService Shutdown关闭
当你使用ExecutorService的时候,你应该记得关闭它,这样这些被管理的线程才会停止运行。
举例:如果你的应用通过main()方法启动,并且你的 应用中存在一个 激活的 ExecutorService,那么即使你的main thread(main线程)已经退出了,这个应用依然会在后台运行。 原因: ExecutorService中的活跃线程,防止了jvm关闭ExecutorService。
结论:jvm是可能无法关闭ExecutorService的,如果某些情况下,你不希望ExecutorService在后台不受控制的执行,那你在必要的时候 需要手动调用 ExecutorService中的shutdown方法。
通过调用ExecutorService中的shutdown方法可以终止该ExecutorService中的线程,但是ExecutorService并不会立即关闭,但是ExecutorService已经不会再接收新的task了,等到所有的thread完成各自的task,那么这个ExecutorService就会关闭。并且所有task中的结果 会在shutdown方法执行之前 submit(提交),都是已经执行完成了的。并不会存在没有的执行的task。
结论:手动调用shutdown并不会立即关闭ExecutorService,而是等待ExecutorService中所有的任务完成,并且提交之后,才会关闭的。(所以手动调用shotdown方法,可以不必担心存在剩余任务没有执行的情况)
如果你想立即关闭一个ExecutorService,你可以调用shutdownNow方法来实现。调用这个方法,ExecutorService将会”尝试着“关闭所有正在执行的task,这个关闭的过程会自动跳过那些已经submit的task(节省性能)。但是 对于那些正在 执行的task,并不能保证他们就一定会直接停止执行,或许他们会暂停,或许会执行直到完成,但是ExecutorService会尽力关闭所有正在运行的task。
网友评论