多线程的实现方法三:利用Callable,FutureTask接口实现 * 1.得到任务对象 * 1.1定义类实现Callable接口,重写call方法(可以返回结果),封装要做的事 * 1.2用FutureTask把Callable对象封装成任务对象 * 2.把线程任务对象交给Thread处理 * 3.调用Thread的start方法启动线程,执行任务 * 4.线程执行完毕后,通过futureTask的get方法去获取任务执行的结果 * 方法名称 说明 * publce FutureTask<>(Callable call) 把Callable对象封装成FutureTask对象 * public v get()throws Exception 获取线程执行Call方法返回的结果 * 方式三优缺点: * 优点:线程任务只是实现接口,可以继续继承类和实现接口,扩展性强 * 可以在线程执行完毕后去获取线程执行的结果 * 缺点:编码复杂一些
/* * 目标:学会创建方式三:实现Callable接口,结合futureTask方法 * */ public class ThreadDemo3 { public static void main(String[] args) { //3.创建callable任务对象 Callable<String> call=new MyCallable(100); //4.把callable任务对象封装成futureTask对象 //futureTask作用:(futureTask属于runnable)可以交给thread //futureTask作用:可以在线程执行完毕以后通过调用其get方法得到线程执行的结果 FutureTask<String> f1=new FutureTask<>(call); //5.交给线程处理 Thread t1=new Thread(f1); t1.start(); Callable<String> call2=new MyCallable(200); FutureTask<String> f2=new FutureTask<>(call2); Thread t2=new Thread(f2); t2.start(); try { //如果f1.f2任务没有执行完毕,这里的代码会等待,直接线程跑完才会取结果 String rs1= f1.get(); System.out.println("第一个结果:"+rs1); String rs2= f2.get(); System.out.println("第二个结果:"+rs2); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } //1.定义一个任务类,实现Callable(因为要返回结果,所以是泛型),应该声明线程任务执行完毕后的数据类型 class MyCallable implements Callable<String> { private int n; public MyCallable(int n) { this.n = n; } //2.重写call方法(线程的任务方法) @Override public String call() throws Exception { int sum=0; for (int i = 1; i <=n ; i++) { sum+=i; } return "子线程执行的结果事:"+sum; } }
----------------------------------------------------------------------------------------------
Thread常用方法,构造器 * 方法名称 说明 * String getName() 获取当前线程的名称,默认线程名称是Thread-索引 * void setName(String name) 设置线程名称 * public static Thread currentThread() 返回对当前正在执行的线程对象的引用 * public static void sleep(long time) 让线程休眠指定的时间,单位为毫秒 * public void run() 线程任务方法 * public void start() 线程启动方法
--------------------------------------------------------------------------------------------------------------
线程安全问题: * 多个线程同时操作同一个共享资源的时候可能会出现业务安全问题,成为线程安全问题 * 出现原因: * 存在多线程并发; * 同时访问共享资源; * 存在修改共享资源;
案例:小明,小红同时在一个有10w元账户里取10w元
public class Account { private String carid; private double money;//账户余额 public Account() { } public Account(String carid, double money) { this.carid = carid; this.money = money; } public String getCarid() { return carid; } public void setCarid(String carid) { this.carid = carid; } public double getMoney() { return money; } public void setMoney(double money) { this.money = money; } //小明 小红 public void drawMoney(double money) { //先获取谁来取钱,线程的命字就是人民 String name=Thread.currentThread().getName(); //1.判断账户是否有钱 if(this.money>=100000){ //2.取钱 System.out.println(name+"来取钱,取出"+money); //3.更新余额 this.money-=money; System.out.println(name+"取钱后,剩余"+this.money); }else { //4.余额不足 System.out.println(name+"来取钱,余额不足"); } } }
public class ThreadSafe1 extends Thread{ //接收处理账户对象 private Account acc; public ThreadSafe1(Account acc,String name){ super(name); this.acc=acc; } @Override public void run() { //小明,小红取钱 acc.drawMoney(100000); } }
/* * 需求:模拟取钱案例(线程安全问题) * */ public class ThreadSafe { public static void main(String[] args) { //1.定义一个线程类,创建一个共享的账户对象 Account acc=new Account("卡号",100000); //2.创建2个线程对象,代表小明和小红同时进来 new ThreadSafe1(acc,"小明").start(); new ThreadSafe1(acc,"小红").start(); } }