多线程:
线程有四种创建方式:
继承Thread,重写run方法
实现Runnable接口
实现Callable接口
线程池
注意: 启动线程就是指请求jvm运行相应的程序
启动线程不代表线程就会立即运行,由线程调度器(scheduler)决定
第一种:
1)继承Thread,并且重写run方法:
重写父类的run()方法
package com.itjh.pojo;
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 200; i++) {
//被调用时获得当前线程的名字,主方法中的`.start()`就表示被调用
System.out.println(getName()+"。。。子线程。。。。。"+i);
}
}
}
2)创建一个主线程:
实例化MyThread类,调用start()方法,意为自动开启线程,并且他会自动去调用MyThread()类中的run()方法
主线程和MyThread子线程的执行顺序与代码放置的顺序是无关的,但是一个方法同一个类中的方法是按照顺序来的,主线程第
执行完毕后才会执行.......主方法.......
package com.itjh.Test;
import com.itjh.pojo.MyThread;
public class Test01 {
public static void main(String[] args) {
MyThread myThread=new MyThread();
//给子线程起个名字!!!
myThread.setName("子线1==");
myThread.start();
for (int i = 0; i < 200; i++) {
System.out.println("主线程"+i);
}
System.out.println(".......主方法.......");
}
}
结果大概这样:
主线程196
主线程197
主线程198
主线程199
子线1==。。。子线程。。。。。132
子线1==。。。子线程。。。。。133
子线1==。。。子线程。。。。。134
子线1==。。。子线程。。。。。135
.......主方法.......
子线1==。。。子线程。。。。。136
子线1==。。。子线程。。。。。137
第二种方法:
1)创建MyRunnable类实现Runnable类,并且重写run()方法
package com.one;
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 300; i++) {
System.out.println("子线程实现Runnable第"+i);
}
}
}
2)创建主线程:
先实例化Thread,将MyRunnable传进去,在Thread类中有很多构造方法:
如:
这里我采用第三个构造函数,传进去一个实现类和自定义线程名
import com.one.MyRunnable;
public class MyRunnableTest {
public static void main(String[] args) {
Thread thread=new Thread(new MyRunnable());
thread.start();
for(int i=0;i<300;i++){
System.out.println("主线程第"+i);
}
}
}
结果是乱序的,也可能是顺序的
第三种:
思路:Callable接口要借助于FutureTask类来创建线程,FutureTask继承了Runnable接口,所以,将他放入Thread实例化进行的构造函数传参中,Thread . start()开启线程
创建新的类实现Callable接口,并且重写其中的call()方法:
package com.itjh.pojo;
import java.util.concurrent.Callable;
public class MyCallable implements Callable {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i < 100; i++) {
sum=sum+i;
}
return sum;
}
}
创建主线程:
package com.itjh.Test;
import com.itjh.pojo.MyCallable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Test03 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//先获得的一个自己创建的MyCallable对象,即子线程
MyCallable myCallable=new MyCallable();
//创建FutureTask接收子线程进行管理,并设置管理的子线程的返回值为Integer
FutureTask<Integer> futureTask=new FutureTask(myCallable);
//FutureTask最终继承了Runnable类,所以直接扔进Tread中
Thread thread=new Thread(futureTask);
thread.start();
//用FutureTask的get()方法获得返回值,并打印
Integer i =futureTask.get();
System.out.println(i);
}
}
为什么不直接将Callable实现类放在Thread实例化中呢?为什么要用要借助FutureTask才能创建基于Callable接口的实现类的线程呢?
1、因为Tread构造方法中没有Callable的返回类型
2、FutureTask实现了RunnableFuture接口,而RunnableFuture接口又继承了Runnable接口,在Thread类中有参数类型为Runnable的构造方法,FutureTask类中有参数类型为Callable的构造函数,综上所述,所以要借助FutureTask创建线程
第四种:
线程池
创建线程的各种方法对比:
图片摘自:https://www.bilibili.com/video/BV1ut411T7Yg?p=8