第一种方式:继承Thread
步骤:
1.创建线程类,继承自Thread + 重写run,run中写线程体,线程体就是mian()函数里面的写法
2.使用线程:
2.1 创建线程对象
2.2 线程对象.start()
步骤展示:
1.
public class Rabbit extends Thread {//线程类,继承自Thread
@Override
public void run() {//在IDEA中可以通过ctrl+o快捷键快速重写父类函数
super.run();
for(int i=0;i<1000;i++){
System.out.println("兔子跑了"+i+"步");
}
}
}
2.
public class RabbitAPP {
public static void main(String[] args){
Rabbit rabbit = new Rabbit();//2.1 创建对象
rabbit.start();//只是加到线程组里面,等待CPU调用。CPU是自动调用的,所以不需要你自己写程序。
//注意,不要调用run方法。如果你调用run方法,相当于是调用函数而已,没有用到线程方面的内容。
}
}
第二种方式:通过Runnable接口
为什么有了第一种方式还要使用第二种方式呢?因为Java只支持单继承,如果一个类必须继承自A类,那就无法继承Thread类,所以必须实现接口来实现多线程。
步骤:
1.类实现Runnable接口+重写run() ------->真实角色类
2.使用线程
2.1 创建真实角色
2.2 创建代理(Thread类)
2.3 代理.start()
这里用到了代理设计模式,你可以先了解一下,基本来说代理设计模式就是:
1.真实类与代理类实现共同接口。
2.代理类中含有真实类引用,并且调用真实类方法。
总结来说就是代理类间接行使真实类的方法。
为什么要这么做呢?你看,哪怕是通过接口,最后还不是要通过Thread类来调用.start()?换句话说,当我们不想或者无法从Thread中继承出类,但是我们还得用Thread类的时候,那我们应该怎么办?
我们应该,想办法将我们写的类和Thread之间构建一个关系。怎么构建关系?把我们写的类当做一个参数传递进去不就好了么。但是问题又来了,我们是把类传递进去了,但是类的写法多样,实现功能也大相径庭,凭什么去保证你的类作为参数传递进Thread的时候,能恰好合适呢?哦,我们可以让他们按照某种规范,或者某种准则。等等,规范?准则?那我懂了,接口!只要让Thread和我们写的类都派生于同一个接口不就好了么?然后在这个接口里写上至少一个必须重写的函数。这样,当我们写的类传递进Thread类的时候,Thread会在内部调用我们的run()函数,而我们无需关系Thrad在内部做了些什么,岂不美哉?
好了,下面给出实例代码:
1.
package com.njust.MyThread;
public class Programmer implements Runnable {
@Override
public void run() {
for(int i=0;i<1000;i++)
System.out.println("一边敲代码");
}
}
2.
package com.njust.MyThread;
public class ProgrammerApp {
public static void main(String[] args){
Programmer programmer = new Programmer();
Thread proxy = new Thread(programmer);
proxy.start();
for(int i=0;i<1000;i++)
System.out.println("一边聊QQ");
}
}
第三种方式:通过Callable接口
好处是可以返回值,也能抛出异常。Callable时Runnable的加强版。
1.创建Callable实现类+重写call
2.借助 执行调度服务 ExecutorService,获取Future对象
ExecutorService ser = Executors.newFixedThreadPool(n);//n代表开启多少个线程
Future result = ser.submit(实现类对象)
3.获取值reslut.get();
4.停止服务ser.shutdownNow();
package com.njust.MyThread;
import java.util.concurrent.*;
public class Call {
public static void main(String[] args){
ExecutorService executorService = Executors.newFixedThreadPool(1);
Race racer = new Race();
Future<Integer> res = executorService.submit(racer);
int num = 0;
try {
num = res.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
executorService.shutdownNow();
System.out.println(num);
}
}
class Race implements Callable<Integer> {//这里的泛型是返回值类型
@Override
public Integer call() throws Exception {
return 1000;
}
}