1、继承Thread类
创建一个任务类继承Thread类型,重新run方法表示一个具体的任务,在主方法中创建一个线程兑现(任务类对象),然后启动线程。
注:新线程的创建和启动都需要借助主线程
一旦新线程启动之后,两个线程之间互不影响
启动线程方法:start();
public class 设置线程名称 {
public static void main(String[] args) {
MyTread myThread = new MyThread();
myThread.start();//借助主线程的帮助
for (int i = 0; i < 10; i++) {
System.out.println("主线程启动");
}
}
}
class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("新线程启动");
}
}
2、实现Runnable接口
创造一个任务类实现Runnable接口,重写run方法表示需要执行的任务,创建一个任务类对象,表示一个具体任务,然后再创建一个Thread类的线程对象,将任务对象提交给线程对象。
public class 多线程的第二种实现方式{
public static void main(String[] args) {
//3、创建任务类对象
MyRunable myRunable = new MyRunnable();
//4、创建Thread对象,把任务类交给他
Thread thread = new Thread(myRunnable);
//5、开启线程
thread.start();
for (int i = 0; i < 1000; i++) {
System.out.println("主线程.............");
}
}
}
//1、创建一个任务类实现Runnable接口
class MyRunnable implements Runnable{
//2、重写run方法,表示具体的任务
@Override
public void run(){
for(int i =0;i< 1000; i++){
System.out.println("MyRunnable的run方法")
}
}
}
3、实现callable接口
创建一个任务类实现callable接口,重写call()方法,然后创建任务类对象,再创建Future的实现类FutureTask对象,把任务类对象作为构造方法的参数传递,创建Thread对象,把FutureTask对象作为构造方法的参数传递,最后启动线程。 get方法可以获取线程结束之后的结果。
callable接口可以定义返回值。
public class 多线程的第三种实现方式 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//3、创建任务类对象
Mycallable mycallable = new Mycallable();
//4、创建FutureTask对任务类进行包装(把任务类作为构造参数
//传递给FutureTask)
FutureTask<String> futureTask = new FutureTask<>(mycallable);
//5、创建线程对象 传递futureTask
Thread thread = new Thread(futureTask);
//6、启动线程
thread.start();
//7、get方法可以获取任务类的返回值
String str = futureTask.get();
System.out.println(str);
}
}
//1、定义一个任务类 实现Callable接口
class Mycallable implements Callable<String>{
//2、重写call方法 表示具体的任务
@Override
public String call() throws Exception {
for (int i = 1000; i >= 0; i--) {
System.out.println("掉了"+i+"根头发");
}
return "掉完了,成了一个大光头";
}
}
继承方式和实现方式的区别
1、代码复杂程度:
继承Thread方式简单
实现Runnable接口的方式比较复杂
2、实现原理:
继承Thread:
在调用start()方法时,底层会调用start0()方法,该方法是native修饰,表示的是本地的方法(是用C语言写的,所以看不见),然后回头再调用run方法,因为我们重写了run方法,最后执行的是我们重写后的run方法。
实现Runnable接口:
在创建Thread对象时,调用有参构造(Runnable任务类对象),一路调用init方法,最终将传进去的Runable任务对象赋值给自己的成员变量target,在嗲用start方法时,底层会调用start0方法(与继承Thread方法一致),该方法是native修饰,代表本地方法,回头再调用run方法,会进行if判断:判断自己的成员变量target是否为空,不为空则调用target,run()
3、设计层面:
java中只支持单继承,不支持多继承
继承方式:某个类继承了Thread类,那么就无法继承其他业务中需要的类型,就限制了我们的设计,扩展性较差。
实现方式:某个类通过实现Runnable的方式完成了多线程的设计,仍然可以继承当前业务中的其他类型,扩展性较强。
4、灵活性
继承方式:将线程对象和任务内容绑定在了一起,耦合性较强,灵活性较差。
实现方式:将线程对象和任务对象分离,耦合性就降低,灵活性增强:同一个任务可以被多个线程对象执行,某个线程对象也可以执行其他的任务对象。并且将来还可以将任务类对象,提交到线程池中运行;任务类对象可以被不同线程运行,方便进行线程之间的数据交互。