实现Runnable接口(底层 实现)
继承Thread类
实现Callable接口(进阶)
先看Runnable源码,是我们1.0版本就有的且在java.lang包下的
package java.lang;
/*
* @author Arthur van Hoff
* @see java.lang.Thread 线程类继承了Runnable
* @see java.util.concurrent.Callable 被包装成Thread才能运行
* @since JDK1.0
*/
@FunctionalInterface // 这是函数式接口
public interface Runnable {
/**
* When an object implementing interface Runnable
is used
* to create a thread, starting the thread causes the object's
* run
method to be called in that separately executing
* thread.
*
* The general contract of the method run
is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
由上图可知,Runnable接口仅此一个无返回值的run方法,并且是函数式接口修饰类,那么我们可以用lambda表达式来简写代码。
实现Runnable接口创建一个线程。
public class ThreadDemo2 implements Runnable {
private static int ticket = 10;
@Override
public void run() {
while (ticket > 0) {
// Thread.currentThread().getName()获取当前操作该类的线程名
System.out.println(Thread.currentThread().getName() + "拿走第" + ticket--);
}
}
public static void main(String[] args) {
ThreadDemo2 threadDemo1 = new ThreadDemo2();
// 如果直接run就是调用一个普通类的一个方法,就体会不到多线程抢占时间片
// threadDemo1.run();
// 把实现Runnable接口的类当作Thread类的构造方法入参,此时,多个Thread传如同一个入参
new Thread(threadDemo1, "线程1").start();
new Thread(threadDemo1, "线程2").start();
}
}
执行main方法可以 得知我们发现线程不安全(打印票数大于10),由于工作内存和主内存之间进行copy操作,会导致工作内存的数据不正确。
我们发现Thread类实现了Runnable接口,为什么有了Runnable还要写个Thread尼?
因为我们定义个Runnable接口并没有真正创建线程,只是一个普通的Java接口而已,而真正实现我们创建线程的功能都在Thread类中。
public class ThreadDelete extends Thread {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"执行了"+i);
}
}
public static void main(String[] args) {
ThreadDelete threadDelete1 = new ThreadDelete();
threadDelete1.setName("线程A");
threadDelete1.start();
ThreadDelete threadDelete2 = new ThreadDelete();
threadDelete2.setName("线程B");
threadDelete2.start();
}
}
首先拿出 callable 源码文件,是5版本后才有的并在在JUC(java.util.concurrent)包下
package java.util.concurrent;
/**
* A task that returns a result and may throw an exception.
* Implementors define a single method with no arguments called
* {@code call}.
*
* The {@code Callable} interface is similar to {@link
* java.lang.Runnable}, in that both are designed for classes whose
* instances are potentially executed by another thread. A
* {@code Runnable}, however, does not return a result and cannot
* throw a checked exception.
*
*
The {@link Executors} class contains utility methods to
* convert from other common forms to {@code Callable} classes.
*
* @see Executor
* @since 1.5
* @author Doug Lea
* @param the result type of method {@code call}
*/
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
我们可以看到,Callbale和Runnable非常相似,都是一个接口且是函数式接口(只有一个方法)。值得注意的是Callable的call方法是有返回值的,可以抛出异常的一个方法;Future会在另一篇文章上讲。
public class ThreadDemo4 implements Callable<Boolean> {
@Override
public Boolean call() throws Exception {
System.out.println("执行的线程是:" + Thread.currentThread().getName());
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
ThreadDemo4 t1 = new ThreadDemo4();
ThreadDemo4 t2 = new ThreadDemo4();
ThreadDemo4 t3 = new ThreadDemo4();
// 创建一个线程池
ExecutorService service = Executors.newFixedThreadPool(5);
// 提交一个任务给操作系统,返回一个异步结果
Future<Boolean> r1 = service.submit(t1);
// 这里的get是一个阻塞的,如果有值才会返回
System.out.println("获取线程的返回值为"+r1.get());
service.submit(t2);
service.submit(t3);
// 使用lambda表达式简化书写
System.out.println(service.submit(() -> {
System.out.println("这是lambda表达式实现线程"+Thread.currentThread().getName());
// 返回值是个泛型
return 1 > 2 ? "returnSomething" : 3;
}).get());
// 关闭线程池
service.shutdown();
}
}
需求:我登录淘宝,获得积分信息,获得收货地址信息,获得订单信息。
分析需求:以上三个需求并没有依赖关系,顺序没有要求。
原始实现:
package com.yang;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* @author: fudy
* @date: 2020/9/11 下午 08:18
* @Decription: 模拟登录淘宝获取积分信息,收获地址,订单信息
**/
public class IndexController {
public static void main(String[] args) throws InterruptedException {
// 获取当前系统毫秒值
long currentBeginTime = System.currentTimeMillis();
// 模拟服务执行
Integral.getIntegral();
ShippingAddress.getShippingAddress();
OrderInfo.getOrderInfo();
long currentEndTime = System.currentTimeMillis();
System.out.println("程序执行了:"+(currentEndTime-currentBeginTime)+"ms");
}
}
class Integral{
public static Long getIntegral() throws InterruptedException {
// 模拟查询数据库以及逻辑处理操作
TimeUnit.SECONDS.sleep(3);
System.out.println("获取用户积分为10积分");
return 10L;
}
}
class ShippingAddress{
public static List<String> getShippingAddress() throws InterruptedException {
TimeUnit.SECONDS.sleep(2);
System.out.println("获取用户收获地址信息");
return new ArrayList<>();
}
}
class OrderInfo{
public static List<String> getOrderInfo() throws InterruptedException {
TimeUnit.SECONDS.sleep(5);
System.out.println("获取用户订单信息");
return new ArrayList<>();
}
}
控制台打印:10007ms
我们可以知道,程序是串行的,那么应该是3+2+5=10秒左右!业务量越多,则耗时越长!
我们利用多线程并行处理
package com.yang;
import java.util.List;
import java.util.concurrent.*;
/**
* @author: fudy
* @date: 2020/9/11 下午 08:29
* @Decription:
**/
public class IndexPlusController{
public static void main(String[] args) throws InterruptedException, ExecutionException {
long currentBeginTime = System.currentTimeMillis();
// 利用Callable多线程执行
// 创建线程池
ExecutorService service = Executors.newFixedThreadPool(5);
// 执行任务
Future<Long> longFuture = service.submit(new IntegralCallable());
Future<List<String>> listFuture = service.submit(new ShippingAddressCallable());
Future<List<String>> submit = service.submit(new OrderInfoCallable());
// 此处get方法是阻塞的,不能 List shippingAddress = service.submit(new ShippingAddressCallable()).get();
List<String> shippingAddress = listFuture.get();
Long integral = longFuture.get();
List<String> orderInfo = submit.get();
long currentEndTime = System.currentTimeMillis();
System.out.println("程序执行了:"+(currentEndTime-currentBeginTime)+"ms");
service.shutdown();
}
}
class IntegralCallable implements Callable<Long>{
@Override
public Long call() throws Exception {
return Integral.getIntegral();
}
}
class ShippingAddressCallable implements Callable<List<String>> {
@Override
public List<String> call() throws Exception {
return ShippingAddress.getShippingAddress();
}
}
class OrderInfoCallable implements Callable<List<String>> {
@Override
public List<String> call() throws Exception {
return OrderInfo.getOrderInfo();
}
}
执行结果是:5009ms,不愧是我!!
程序并行后,如果此方法需要调用三个服务,那么服务耗时最长的时间会作为系统的瓶颈,而不是业务量的多少!