一、前言
进程(process)是大概念,进程里面可以有多个线程(thread)
进程是执行过程,是独立的执行路径
多任务:同时干多件事
守护线程与非守护线程
守护线程是区别于用户线程,用户线程即我们手动创建的线程,而守护线程是程序运行的时候在后台提供一种通用服务的线程。垃圾回收线程就是典型的守护线程。
main是非守护线程。main线程是由java虚拟机在启动的时候创建的。main方法开始执行的时候,主线程已经创建好并在运行了。
二、三种线程的创建方式
(一)继承Thread类
流程:
1、自定义线程类继承Thread类
2、重写run()方法,编写线程执行体
3、创建线程对象,调用start()方法启动线程
创建自定义类并重写run()方法
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("狗上山---" + i);
}
}
}
创建线程对象,调用start()方法启动线程
public class Test {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
for (int i = 0; i < 100; i++) {
System.out.println("狗下山---"+i);
}
}
}
输出
.....
狗下山---83
狗下山---84
狗下山---85
狗下山---86
狗下山---87
狗下山---88
狗下山---89
狗下山---90
狗下山---91
狗下山---92
狗上山---89
狗上山---90
狗上山---91
狗上山---92
狗上山---93
狗上山---94
狗上山---95
狗上山---96
狗上山---97
狗上山---98
狗上山---99
狗下山---93
狗下山---94
狗下山---95
狗下山---96
狗下山---97
狗下山---98
狗下山---99
两个线程交替进行。
不建议使用Thread,因为Java单继承的局限性
(二)实现Runnable接口
1、定义MyRunnable类实现Runnable接口
2、实现run()方法,编写线程执行体
3、创建线程对象,调用start()方法启动线程
定义MyRunnable类实现Runnable接口,并实现run方法
public class MyRunnable implements Runnable{
@Override
public void run() {
for(int i=0; i<200; i++){
System.out.println("狗上山"+i);
}
}
}
创建线程对象,并调用start()方法启动线程
public class Test {
public static void main(String[] args) {
// 创建runnable 接口的实现类对象
MyRunnable myRunnable = new MyRunnable();
// 创建线程对象,通过线程对象开启线程
new Thread(myRunnable).start();
for (int i = 0; i < 100; i++) {
System.out.println("狗子下山---"+i);
}
}
}
输出
...
狗子下山---85
狗子下山---86
狗子下山---87
狗子下山---88
狗子下山---89
狗子下山---90
狗子下山---91
狗上山0
狗子下山---92
狗上山1
狗子下山---93
狗子下山---94
狗子下山---95
狗上山2
狗上山3
狗子下山---96
狗子下山---97
狗子下山---98
狗子下山---99
狗上山4
狗上山5
狗上山6
狗上山7
狗上山8
狗上山9
狗上山10
...
(三)实现Callable接口
Callable与Thread和Runable的区别在于可以返回数据。
1、实现Callable接口,需要返回值类型
2、重写call方法,需要抛出异常
3、创建目标对象
4、创建执行服务:ExecutorService service = Executors.newFixedThreadPool(1);
5、提交执行:
Future<Boolean> result1 = ser.submit(t1);
6、获取结果:boolean r1 = result1.get()
7、关闭服务: service.shutdownNow();
实现接口、重写call
public class MyCallable implements Callable {
int num;
public MyCallable(int num){
this.num = num;
}
@Override
public Boolean call() throws Exception { //可以设置返回数据类型
System.out.println("狗上山==="+num);
return true; }
}
创建目标对象、创建执行服务、提交执行、获取结果、关闭服务
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 创建目标对象
MyCallable myCallable1 = new MyCallable(1);
MyCallable myCallable2 = new MyCallable(2);
MyCallable myCallable3 = new MyCallable(3);
// 创建线程池执行服务
ExecutorService service = Executors.newFixedThreadPool(3);
// 提交执行
Future<Boolean> s1 = service.submit(myCallable1);
Future<Boolean> s2 = service.submit(myCallable2);
Future<Boolean> s3 = service.submit(myCallable3);
// 获取结果
boolean ss1 = s1.get();
boolean ss2 = s2.get();
boolean ss3 = s3.get();
// 关闭服务
service.shutdown();
System.out.println(ss1 + "----" + ss2 + "----" + ss3);
}
}
输出
三、线程池
创建线程池的方式多种多样,大家可以根据需求进行填写
选择自定义线程的实现方式,我这里选择的是Runnable
1、实现Runnable接口
2、重写run方法
3、创建目标对象
4、创建执行服务:ExecutorService service = Executors.newFixedThreadPool(3);
5、提交执行:
Future<Boolean> result1 = service.execute(t1);
6、获取结果:boolean r1 = result1.get()
7、关闭服务: service.shutdownNow();
实现接口和重写方法
public class MyRunnable implements Runnable{
String name;
public MyRunnable(String name){
this.name = name;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + name + "上山");
}
}
测试
public class Test {
public static void main(String[] args) {
// 创建目标对象
MyRunnable r1 = new MyRunnable("狗");
MyRunnable r2 = new MyRunnable("猫");
MyRunnable r3 = new MyRunnable("鸟");
// 创建线程池执行服务
ExecutorService service = Executors.newFixedThreadPool(3);
// 执行服务,execute只可以执行Runnable
service.execute(r1);
service.execute(r2);
service.execute(r3);
// 关闭服务
service.shutdown();
}
}
输出