以前的程序,只有main()方法一个执行流程,按顺序执行main()方法中的语句,这种简单的一个流程,不能满足现在的需求,考虑是否可以创建多个互不相干的流程,同时做不同的操作呢?这就是多线程的思想。
一共有三种方法,第三种作为了解,第二种使用最多
创建线程
1、继承Thread类创建线程
- 创建一个类,继承Thread类
- 重写run方法,将想要和主线程同时执行的逻辑代码写进去
- 创建这个类的对象
- 启动线程
分部讲解
创建了一个继承Thread的类,并且重写了run()方法
//这里创建了一个继承Thread的类,并且重写了run()方法
class Thread01 extends Thread{
public void run(){
for(int i=0;i<=10;i++){
System.out.println("线程2:"+i);
}
}
}
public class Demo03 {
//main()方法就是主线程的执行体
public static void main(String[] args) {
创建一个对象,并且,调用他的start方法,启动另一个线程
new Thread01().start();这时候Thread01()中的run()方法和main方法同时执行
for(int i=0;i<=10;i++){
System.out.println("主线程:"+i);
}
}
}
输出结果
主线程:0
线程2:0
线程2:1
线程2:2
线程2:3
线程2:4
主线程:1
线程2:5
主线程:2
线程2:6
主线程:3
线程2:7
线程2:8
线程2:9
主线程:4
线程2:10
主线程:5
主线程:6
主线程:7
主线程:8
主线程:9
主线程:10
可以看到,两个方法交替这输出,两个线程是并行的
2、实现Runnable接口
- 创建一个类,实现Runnable接口,重写run方法
- 创建一个Thread()对象,传入一个实现Runna接口的类的对象
- 调用Thread的star方法启动线程
分布实现
创建一个类,实现Runnable接口,重写run方法
class Thread02 implements Runnable{
@Override
public void run() {
for(int i=0;i<=10;i++){
System.out.println("线程3:"+i);
}
}
}
创建一个Thread()对象,传入一个实现Runna接口的类的对象
public class Demo03 {
public static void main(String[] args) {
//这里是静态代理模式
new Thread(new Thread02()).start();
for(int i=0;i<=10;i++){
System.out.println("主线程:"+i);
}
}
}
输出结果
主线程:0
线程3:0
主线程:1
线程3:1
主线程:2
主线程:3
主线程:4
线程3:2
主线程:5
线程3:3
主线程:6
主线程:7
主线程:8
线程3:4
主线程:9
线程3:5
主线程:10
线程3:6
线程3:7
线程3:8
线程3:9
线程3:10
注:上面代码中:new Thread(new Thread02()).start();使用静态代理模式,可以使用Lambda表达式简化代码
详细的看:Lambda表达式(1)
分析
对于上面两种创建方式,
第一种,继承Thread方法:由于Java中是单继承,所以这个类就不能继承其他类,有很大的局限性,但编写简单,要访问当前线程时,不用Thread.currentThread()获得当前线程对象
第二种,这种实现接口的方法就解决了继承冲突的问题,并且可以实现多个线程共享同一个实现Runna接口的类的对象,适合多个线程处理同一个资源,但时编写比较麻烦
但是这两种方法都有一个缺点,那就是run方法没有返回值,不能传参数,不能声明异常因为接口已经限制了run 方法,所以还有一种不常用的创建现成的方法
3、使用Callable 和Future创建线程
Callable接口很类似于Runna 接口其中提供了一个更强大的方法,call方法,call有返回值,可以声明异常,但是它不能直接传入Thread中。因此还要用到另一个接口Future接口;
步骤如下:
- 创建一个Callable接口的实现类,并实现call()方法,在创建Callable实现类的实例对象
- 使用FutureTask来包装Callable的对象,FutureTask对象封装了Callable对象的call方法的返回值
- 使用FutureTask对象作为Thread的targe创建并启动线程
- 调用FutureTask的get()方法获取子线程执行结束的返回值,会有阻塞
//了解部分
public class Demo04 {
public static void main(String[] args) {
FutureTask<Integer> task=new FutureTask<Integer>(
()->{
int i=0;
for(;i<=10;i++){
System.out.println("线程4:"+i);
}
return i;
}
);
new Thread(task).start();
for(int i=0;i<=10;i++){
System.out.println("主线程:"+i);
}
//获取返回值使用get();
try {
System.out.println(task.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
输出结果
主线程:0
主线程:1
线程4:0
线程4:1
主线程:2
线程4:2
线程4:3
线程4:4
线程4:5
线程4:6
线程4:7
线程4:8
线程4:9
线程4:10
主线程:3
主线程:4
主线程:5
主线程:6
主线程:7
主线程:8
主线程:9
主线程:10
11