JAVA多线程的四种实现方式:
- 继承Thread类
- 实现Rannable接口
- 实现Callable接口通过FutureTask包装器来创建Thread线程
- 通过线程池创建线程,使用线程池接口ExecutorService结合Callable和FutureTask来实现有返回结果的多线程。
前两种【无返回值】原因:通过重写run方法,run方法的返回值是void,所以没有办法返回结果。
后两种【有返回值】原因:通过实现Callable接口,要重写call方法,call方法的返回值类型是object,所以可以将返回的值存在Object对象中
方式一:继承Thread类:
实现步骤:
1.创建一个Thread子类
2.在Thread中重写run(方法),设置线程任务
3.创建线程子类对象
4.调用线程的start方法,开启新的线程,执行run方法里的代码
public class MyThread extends Thread{ //1.继承Thread类
@Override //2.重写run方法,设置线程任务
public void run() {
System.out.println("创建的线程执行了");
}
}
public class ThreadDemo1 {
public static void main(String[] args) {
MyThread myThread1 = new MyThread(); //3.创建线程子类对象
MyThread myThread2 = new MyThread();
myThread1.start(); //调用线程中的start方法,开启新的线程,并执行run方法里的代码
myThread2.start();
System.out.println("主方法中的线程执行了");
}
}
方式二:实现Runnable接口创建线程
如果自己的类已经extends另一个类,就无法直接extends Thread,此时,可以实现一个Runnable接口。
实现步骤:
1.创建一个Runnable实现类
2.实现类中重写run方法,设置线程任务
3.创建一个实现类对象
4.创建一个Thread类对象,并通过构造方法传入一个Runnable实现类对象
5.调用Thread类中的start方法,开启新线程的run方法
public class MyThread implements Runnable{ //1.创建一个Runnable实现类
@Override //2.实现类中重写run方法,设置线程任务
public void run() {
System.out.println("创建的线程被执行了");
}
}
public class ThreadDemo1 {
public static void main(String[] args) {
MyThread myThread = new MyThread(); //创建一个实现类对象
Thread thread = new Thread(myThread); //创建Thread类对象,并通过构造方法传入Runable实现类对象
thread.start(); //调用Thread类中的start方法开启新线程的run方法
System.out.println("主方法中的线程执行了");
}
}
当传入一个Runnable target参数给Thread后,Thread的run()方法就会调用target.run(),参考Thread源码:
@Override
public void run() {
if (target != null) {
target.run();
}
}
实现runnable接口创建线程的好处?
1.避免了java中单继承的局限性,继承了Thread类就无法继承其他类,实现Runnable接口还可以继承其他类,实现其他接口。
2.增强了程序的健壮性,降低了程序的耦合性(解耦)。把设置线程任务和开启线程任务分开,在实现类中重写run方法设置线程任务,在Thread类中调用start方法中开启线程任务,代码可以被多个线程共享,代码和数据之间相互独立
3.线程池中只能存放实现Runnable接口和Callable接口的线程,不能存放继承Thread类的线程
方式三:通过Callable和FutureTask创建线程
实现步骤:
- 创建Callable接口的实现类 ,并实现Call方法
- 创建Callable实现类的实现,使用FutureTask类包装Callable对象,该FutureTask对象封装了Callable对象的Call方法的返回值
- 使用FutureTask对象作为Thread对象的target创建并启动线程
- 调用FutureTask对象的get()来获取子线程执行结束的返回值
public class SomeCallable implements Callable { //创建Callable接口的实现类
@Override
public Object call() throws Exception { //实现call方法
System.out.println("我是通过实现Callable接口通过FutureTask包装器来实现的线程");
return null;
}
}
public class ThreadDemo1 {
public static void main(String[] args) {
System.out.println("我是主方法的线程");
Callable someCallable = new SomeCallable();
由Callable<Integer>创建一个FutureTask<Integer>对象:
FutureTask futureTask = new FutureTask<Object>(someCallable);
注释:FutureTask<Integer>是一个包装器,它通过接受Callable<Integer>来创建,它同时实现了Future和Runnable接口。
Thread thread = new Thread(futureTask);
//由FutureTask<Integer>创建一个Thread对象:
thread.start();
}
}
方式四:通过线程池创建线程
实现步骤:
1.创建线程池工厂类Executors,里面提供静态方法newFixedThreadPool生产一个指定数量的线程池
2.创建一个类,实现Runnable接口重写run方法,设置线程任务
3.调用ExecutorService中的submit方法,传递线程任务,开启线程执行任务
4.调用ExecutorService中的shutdown方法,销毁线程池(不推荐的,一般线程池里的线程用完之后归还即可,没有必要销毁线程池)
public class ThreadPool {
public static void main(String[] args) {
//1.创建线程池工厂类Executors,里面提供静态方法newFixedThreadPool生产一个指定数量的线程池
ExecutorService es = Executors.newFixedThreadPool(3);
Runnable r = new RunnableImpl();
//3.调用ExecutorService中的submit方法,传递线程任务,开启线程执行任务
es.submit(r); //pool-1-thread-2正在运行
es.submit(r); //pool-1-thread-1正在运行
es.submit(r); //pool-1-thread-2正在运行
//4.调用ExecutorService中的shutdown方法,销毁线程池(不推荐的,一般线程池里的线程用完之后归还即可,没有必要销毁线程池)
es.shutdown();
}
}
//2.创建一个类,实现Runnable接口重写run方法,设置线程任务
public class RunnableImpl implements Runnable {
private int tickets =100;
Object obj =new Object();
@Override
public void run() {
// System.out.println(this);
while (true){
synchronized (obj){
if (tickets>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在卖第"+tickets+"张票");
tickets--;
}else {
break;
}
}
}
}
}