1.   什么是并发与并行

要想学习多线程,必须先理解什么是并发与并行

并行:指两个或多个事件在同一时刻发生(同时发生)。

并发:指两个或多个事件在同一个时间段内发生。

2.   什么是进程、线程

进程:

进程是正在运行的程序的实例。

进程是线程的容器,即一个进程中可以开启多个线程。

比如打开一个浏览器、打开一个word等操作,都会创建进程。

线程:

线程是进程内部的一个独立执行单元;

一个进程可以同时并发运行多个线程;

比如进程可以理解为医院,线程是挂号、就诊、缴费、拿药等业务活动

多线程:多个线程并发执行。

3.   线程创建

Java中线程有四种创建方式:

l  继承Thread类

l  实现Runnable接口

l  实现Callable接口

l  线程池

3.1. 继承Thread类

3.1.1.   第一步:创建自定义线程类

package com.creatThera;

import java.util.Date;

/**
* @Auther: lanhaifeng
* @Date: 2019/11/20 0020 09:20
* @Description: 继承Thread类实现多线程
* @statement:
*/
public class MyThread extends Thread{ public void run() {
for (int i = ; i<; i++){
System.out.println("mythread线程正在执行:"+i);
}
} public static void main(String[] args) {
MyThread myThread=new MyThread();
myThread.start();
for (int i = ; i<; i++){
System.out.println("主线程正在执行:"+i);
}
}
}

执行效果如下:

3.2. 实现Runnable接口

3.2.1.   第一步:创建自定义类实现Runnable接口

package com.creatThera;

/**
* @Auther: lanhaifeng
* @Date: 2019/11/20 0020 09:32
* @Description:实现runnable接口创建线程
* @statement:
*/
public class MyRunable implements Runnable { public void run() {
for (int i = ; i<; i++){
System.out.println("myRunnable线程正在执行:"+i);
}
} //测试线程
public static void main(String[] args) {
Thread thread=new Thread(new MyRunable());
thread.start();
for (int i = ; i<; i++){
System.out.println("主线程正在执行:"+i);
}
}
}

执行效果如下:

3.3. 实现Callable接口

3.3.1.   FutureTask介绍

Callable需要使用FutureTask类帮助执行,FutureTask类结构如下:

Future接口:

判断任务是否完成:isDone()

能够中断任务:cancel()

能够获取任务执行结果:get()

3.3.2.   第一步:创建自定义类实现Callable接口

package com.creatThera;

import java.util.concurrent.*;

/**
* @Auther: lanhaifeng
* @Date: 2019/11/20 0020 09:41
* @Description: 实现callable接口创建线程
* @statement: callable接口是有返回值的
*/
public class MyCallnable implements Callable<String> { public String call() throws Exception {
for (int i = ; i < ; i++) {
System.out.println("myCallable线程正在执行:"+i);
}
return "MyCallabe线程执行完毕";
} //测试
public static void main(String[] args) {
//创建futuretask对象
FutureTask<String> futureTask = new FutureTask<String>(new MyCallnable());
//创建Thread对象,传入futureTask
Thread thread=new Thread(futureTask);
thread.start();
for (int i = ; i<; i++){
System.out.println("主线程正在执行:"+i);
}
}
}

运行效果图如下:

3.4. 线程池-Executor

3.4.1.   线程池线类关系图

Executor接口

  声明了execute(Runnable runnable)方法,执行任务代码

ExecutorService接口:

  继承Executor接口,声明方法:submit、invokeAll、invokeAny以及shutDown等

AbstractExecutorService抽象类:

  实现ExecutorService接口,基本实现ExecutorService中声明的所有方法

ScheduledExecutorService接口:

  继承ExecutorService接口,声明定时执行任务方法

ThreadPoolExecutor类:

  继承类AbstractExecutorService,实现execute、submit、shutdown、shutdownNow方法

ScheduledThreadPoolExecutor类:

  继承ThreadPoolExecutor类,实现ScheduledExecutorService接口并实现其中的方法

Executors类:

  提供快速创建线程池的方法

3.4.2.   第一步:创建自定义类实现Runnable接口

package com.creatThera;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /**
* @Auther: lanhaifeng
* @Date: 2019/11/20 0020 09:52
* @Description:使用线程池创建线程
* @statement:
*/
public class MyExecutors { //实现runnable接口,线程池只支持runnable和callable
class MyRunnable implements Runnable{
public void run() {
for (int i = ; i<; i++){
System.out.println("myRunnable线程正在执行:"+i);
}
}
} //测试用线程池创建线程
public static void main(String[] args) {
//1.使用Executors创建线程池
ExecutorService executorService = Executors.newFixedThreadPool();
//2.通过线程池执行线程,线程池只支持runnable和callable
executorService.execute(new MyRunable());
//3.主线程循环打印
for (int i=; i<; i++){
System.out.println("main主线程正在执行:"+i);
}
} }
实现效果如下:

3.5. 小结

3.5.1.   实现接口和继承Thread类比较

l  接口更适合多个相同的程序代码的线程去共享同一个资源。

l  接口可以避免java中的单继承的局限性。

l  接口代码可以被多个线程共享,代码和线程独立。

l  线程池只能放入实现Runable或Callable接口的线程,不能直接放入继承Thread的类。

扩充:

在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。

3.5.2.   Runnable和Callable接口比较

相同点:

l  两者都是接口;

l  两者都可用来编写多线程程序;

l  两者都需要调用Thread.start()启动线程;

不同点:

l  实现Callable接口的线程能返回执行结果;而实现Runnable接口的线程不能返回结果;

l  Callable接口的call()方法允许抛出异常;而Runnable接口的run()方法的不允许抛异常;

l  实现Callable接口的线程可以调用Future.cancel取消执行 ,而实现Runnable接口的线程不能

注意点:

Callable接口支持返回执行结果,此时需要调用FutureTask.get()方法实现,此方法会阻塞主线程直到获取‘将来’结果;当不调用此方法时,主线程不会阻塞!

最新文章

  1. 多重共线性的解决方法之——岭回归与LASSO
  2. MySQL下载及安装
  3. SDUT 3311 数据结构实验之串三:KMP应用
  4. 虚拟目录里面的webconfig不继承网站的设置
  5. 【LeetCode】231 - Power of Two
  6. x86、i386、i486、i586、i686和x86_64
  7. javascript高级编程笔记01(基本概念)
  8. 关于数组和List之间相互转换的方法
  9. 用htaccess进行访问控制(转)
  10. rowspan和colspan
  11. 拔一拔 ExtJS 3.4 里你遇到的没遇到的 BUG(1)
  12. 当页面加载完成时,JQ触发添加页面的元素的事件触发不了。。
  13. 第一次作业:我与CS的缘分
  14. 如何从0开发一个Atom组件
  15. 外贸圈 贸易经 外贸心路 一位成功外贸人的SOHO心得
  16. localhost/get/user.json localhost/get/user.xml
  17. user_agent
  18. Visual Studio 2013 智能提示功能消失解决办法
  19. mongo数据库命令简单学习
  20. 国际音标en

热门文章

  1. 安装VMware Tools的步骤
  2. Mac下Mysql配置
  3. Go基本运行编译命令解释
  4. async和await执行顺序
  5. Android AMS服务
  6. python 连接 redis cluster 集群
  7. Java Excel 导入导出(二)
  8. 事物分析、静态分析(结构分析)与UML
  9. [Schematics] 2. EJS
  10. python 日期、时间、字符串相互转换(转载)