1 Java中实现多线程(一)
- 在Java中负责多线程的功能的类是
java.lang.Thread
包 - 可以通过创建
Thread
的实例来创建新的线程 - 每个线程都是通过某个特定
Thread
对象所对应的方法run()
来完成其操作的,方法run()
称为线程体 - 通过调用
Thread
类的start()
方法来启动一个线程
/**
* 多线程实现龟兔赛跑
*
* @author Administrator
*
*/
public class RabbitTortoiseApp {
public static void main(String[] args) {
Rabbit r = new Rabbit();
Tortoise t = new Tortoise();
r.start(); // 启动线程,内部调用run()方法
t.start();
}
}
class Rabbit extends Thread {
/*
* 继承Thread类,创建线程体
*/
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("兔子:" + i);
}
}
}
class Tortoise extends Thread {
/*
* 继承Thread类,创建线程体
*/
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("乌龟:" + i);
}
}
}
2 Java中实现多线程(二)
2.1 Thread 和 Runnable 的区别
- 继承
Thread
类方式的缺点:如果类已经从一个类继承,则无法再继承Thread
类 - 解决办法:实现
Runnable
接口实现多线程 - 优点:可以同时实现继承,更加通用
/**
* Runnable接口模拟12306抢票
*
* @author Administrator
*
*/
public class RunnableWeb12306APP implements Runnable {
private int num = 10;
public static void main(String[] args) {
// 创建真实对象
RunnableWeb12306APP web12306 = new RunnableWeb12306APP();
// 创建代理对象
Thread t1 = new Thread(web12306, "顾客1");
Thread t2 = new Thread(web12306, "顾客2");
Thread t3 = new Thread(web12306, "顾客3");
// 抢票
t1.start();
t2.start();
t3.start();
}
@Override
public void run() {
while(true) {
if (num <= 0) {
break;
}
// 打印线程的名称
System.out.println(Thread.currentThread().getName() + ":抢到了" + num + "号票");
num--;
}
}
}
2.2 静态代理设计模式
Runnable
接口采用静态代理的设计模式,必需条件有
- 具有真实的角色
- 需要有一个代理角色
- 真实角色和代理角色实现了相同的接口
/**
* 静态代理模拟买房
*
* @author Administrator
*
*/
public class StaticPrexyTest {
public static void main(String[] args) {
HouseBuyer zhangsan = new HouseBuyer("张三", 100);
HouseBuyer lisi = new HouseBuyer("李四", 500);
HouseCompany houseCompany = new HouseCompany(zhangsan);
houseCompany.buyHouse();
houseCompany = new HouseCompany(lisi);
houseCompany.buyHouse();
}
}
/*
* 真实角色:房产买方 实现购买接口
*/
class HouseBuyer implements buy {
private String name;
private int prize;
public HouseBuyer(String name, int prize) {
this.name = name;
this.prize = prize;
}
@Override
public void buyHouse() {
System.out.println("我是" + this.name + ",我要买房,我的心理价位是:" + this.prize + "万");
}
}
/*
* 代理角色:房产中介 实现购买接口
*/
class HouseCompany implements buy {
private HouseBuyer houseBuyer;
public HouseCompany(HouseBuyer houseBuyer) {
this.houseBuyer = houseBuyer;
}
// 寻找房源
private void findHouse() {
System.out.println("寻找房源");
}
// 谈价
private void prize() {
System.out.println("谈价");
}
@Override
public void buyHouse() {
this.houseBuyer.buyHouse();
findHouse();
prize();
}
}
/*
* 共同实现的买房接口
*/
interface buy {
// 买房接口
public abstract void buyHouse();
}
3 Java中实现多线程(三)
- 通过
Callable
接口实现多线程
Callable
和Future
接口
Callable
接口:Callable
是类似于Runnable
的接口,实现Callable
接口的类和实现Runnable
的类都是可以被其他线程执行的任务。Future
接口:表示异步计算的结果,它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future
对象可了解任务执行的情况,可取消任务的执行,还可获取任务执行的结果
Callable
和Runnable
的区别:
Callable
规定的方法是call()
,而Runnable
规定的方法是run()
call()
方法可抛出异常,而run()
方法不能抛出异常Callable
的任务执行后可返回值,运行Callable
任务可取得一个Future
对象,而Runnable
的任务不能返回值
- 思路:
- 创建
Callable
实现类,重写call()
- 借助执行调度服务
ExecutorService
获取Future
对象 - 获取值
result.get()
- 停止服务
ser.shutdownNow()
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* 通过Callable接口实现龟兔赛跑
*
* @author Administrator
*
*/
public class CallRabbitTortoiseApp {
public static void main(String[] args) {
// 创建两个线程,一个兔子,一个乌龟
ExecutorService ser = Executors.newFixedThreadPool(2);
// 创建两个真实对象
Race rabbit = new Race("兔子", 500);
Race tortoise = new Race("乌龟", 1000);
// 获取返回值
Future<Integer> rabbitStep = ser.submit(rabbit);
Future<Integer> tortoiseStep = ser.submit(tortoise);
try {
Thread.sleep(2000); // 跑两秒
rabbit.setFlag(false); // 终止线程
tortoise.setFlag(false);
System.out.println(rabbit.getName() + ":" + rabbitStep.get() + "步");
System.out.println(tortoise.getName() + ":" + tortoiseStep.get() + "步");
} catch (Exception e) {
e.printStackTrace();
} finally {
ser.shutdownNow();
}
}
}
class Race implements Callable<Integer> {
private boolean flag = true;
private String name = null;
// 每一步的时间
private long perStepTime = 0;
// 总步数
private int step = 0;
public Race(String name, long perStepTime) {
this.name = name;
this.perStepTime = perStepTime;
}
public String getName() {
return name;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public Integer call() throws Exception {
while (isFlag()) {
Thread.sleep(perStepTime);
this.step++;
}
return this.step;
}
}