1.多线程如何实现
2.多线程如何保证安全性/同步
3.线程间如何通讯
注意:在多线程try catch finally语句中,当try字段中线程处于等待或者睡眠,finally代码块仍然执行。即finally即使是线程等待或者睡眠仍然执行
Runnable实现类有一个FutureTask
Furure接口实现线程直接数据的交互(Runnable接口不可以,因为Runnable接口的run方法返回值是void)
FutureTask的构造函数,传入Callable接口
callable接口特点
Callable实现的未来任务
1 未来任务的get()方法会阻塞主线程的执行(主线程需要得到未来任务的返回值)
2 一个任务不能被反复执行,如果想反复执行,必须重新设置新任务
笔试题:
价格比对程序
Main
可以根据当前用户输入的商品名称,同时查询淘宝京东天猫的该商品的价格(并行),然后将查询结果返回给main主线程,在主线程中列出不同商店的商品价格列表
public class MyShopTest {
public static void main(String[] args) throws InterruptedException, ExecutionException {
// 资源类
MyShop myShop = new MyShop();
// 淘宝任务
MyCallableDemo myCallableDemoForTb = new MyCallableDemo();
myCallableDemoForTb.setShopName("tb");
FutureTask<Double> tbTask = new FutureTask<Double>(myCallableDemoForTb);
// 京东任务
MyCallableDemo myCallableDemoForJd = new MyCallableDemo();
myCallableDemoForJd.setShopName("jd");
FutureTask<Double> jdTask = new FutureTask<Double>(myCallableDemoForJd);
// 天猫任务
MyCallableDemo myCallableDemoForTmall = new MyCallableDemo();
myCallableDemoForTmall.setShopName("tmall");
FutureTask<Double> tmallTask = new FutureTask<Double>(myCallableDemoForTmall);
// 查询淘宝价格的线程
new Thread(tbTask,"华为手机").start();
// 查询京东价格
new Thread(jdTask,"华为手机").start();
// 查询天猫价格
new Thread(tmallTask,"华为手机").start();
// 返回任务执行结果
Double tbPrice = tbTask.get();//3
Double jdPrice = jdTask.get();//5
Double tmallPrice = tmallTask.get();//2
System.out.println("淘宝价格为:"+tbPrice);
System.out.println("京东价格为:"+jdPrice);
System.out.println("天猫价格为:"+tmallPrice);
System.out.println("=============某某商店价格发生变化,需要重新查询=================");
// 新的查询天猫的线程
new Thread(tmallTask,"华为手机天猫 二次查询").start();
Double double1 = tmallTask2.get();
System.out.println("某某商店最新价格为:"+double1);
}
}
public class MyCallableDemo implements Callable<Double>{
private String shopName;
public void setShopName(String shopName) {
this.shopName = shopName;
}
@Override
public Double call() throws Exception {
// 返回结果
Double price = 0d;
String shop = getShopName();
MyShop myShop = new MyShop();
if(shop.equals("tb")){
price = myShop.taobao();
}else if(shop.equals("jd")){
price = myShop.jingdong();
}else if(shop.equals("tmall")){
price = myShop.tmall();
}
return price;
}
}
运行结果:
Ruuable接口和Callable接口的区别:
1.Ruuable接口是多线程必须实现的接口,Callable接口不是
2.Callable规定的方法是call(),Runnable规定的方法是run().
3.Callable的任务执行后可返回值,而Runnable的任务是不能返回值得
4.call方法可以抛出异常,run方法不可以
5.运行Callable任务可以拿到一个Future对象,Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结果,如果线程没有执行完,Future.get()方法可能会阻塞当前线程的执行;如果线程出现异常,Future.get()会throws InterruptedException或者ExecutionException;如果线程已经取消,会跑出CancellationException。取消由cancel 方法来执行。isDone确定任务是正常完成还是被取消了。一旦计算完成,就不能再取消计算。如果为了可取消性而使用 Future 但又不提供可用的结果,则可以声明Future<?> 形式类型、并返回 null 作为底层任务的结果。