线程实现的三种方式
目录
继承Thread类(重要) #
- 自定义线程类继承Thread类
- 重写run()方法,编写线程执行体
- 创建线程对象,调用start()方法启动线程
实现 #
public class Demo1_CreateThread1 extends Thread {
@Override
public void run() {
//run方法线程体
for (int i = 0; i < 20; i++) {
System.out.println("我在看代码----" + i);
}
}
public static void main(String[] args) {
//main线程,上线程
//创建一个线程对象
Demo1_CreateThread1 testThread = new Demo1_CreateThread1();
//调用start()开启线程
testThread.start();
for (int i = 0; i < 200; i++) {
System.out.println("我在学习多线程----" + i);
}
}
}
总结:线程不一定立即执行,CPU安排调度
案例:(下载图片) #
/**
* 练习Thread,实现多线程同步下载图片
*/
public class Demo2_DownloaderImgCase extends Thread {
private String url;//网络图片地址
private String name;//报错扥文件名
//有参构造
public Demo2_DownloaderImgCase(String url, String name) {
this.url = url;
this.name = name;
}
//下载图片线程的执行体
@Override
public void run() {
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url, name);
System.out.println("下载了文件名为:" + name);
}
public static void main(String[] args) {
Demo2_DownloaderImgCase t = new Demo2_DownloaderImgCase("https://img-home.csdnimg.cn/images/20201124032511.png", "1.png");
Demo2_DownloaderImgCase t1 = new Demo2_DownloaderImgCase("https://img-home.csdnimg.cn/images/20201124032511.png", "2.png");
Demo2_DownloaderImgCase t2 = new Demo2_DownloaderImgCase("https://img-home.csdnimg.cn/images/20201124032511.png", "3.png");
t.start();
t1.start();
t2.start();
}
}
//下载器
class WebDownloader {
//下载方法
public void downloader(String url, String name) {
try {
FileUtils.copyURLToFile(new URL(url), new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO异常,downloader方法出现问题");
}
}
}
实现Runnable接口(推荐) #
推荐使用Runnable对象,因为Java单继承的局限性
- 自定义线程类实现
Runnable
接口 - 实现
run()
方法,编写线程执行体 - 创建线程对象,调用
start()
方法启动对象
实现 #
public class Demo3_CreateRunnable implements Runnable {
@Override
public void run() {
//run方法线程体
for (int i = 0; i < 20; i++) {
System.out.println("我在看代码----" + i);
}
}
public static void main(String[] args) {
//创建runnable接口的实现类对象
Demo3_CreateRunnable testThread = new Demo3_CreateRunnable();
//创建线程对象,通过线程对象来开启我们的线程,代理
Thread thread = new Thread(testThread);
//调用start()开启线程
thread.start();
//new Thread(testThread).start();
for (int i = 0; i < 200; i++) {
System.out.println("我在学习多线程----" + i);
}
}
}
案例:火车票 #
/**
* 多个线程同时操作同一个对象 买火车票案例
*/
//发现问题:多个线程操作同一个资源的情况下,线程不安全,数据紊乱
public class Demo4_TrainTicketsCase implements Runnable {
//票数
private int ticketNums = 10;
@Override
public void run() {
while (true) {
if (ticketNums <= 0) {
break;
}
//捕获异常
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "--->拿到了第" + ticketNums-- + "张票");
}
}
public static void main(String[] args) {
Demo4_TrainTicketsCase ticket = new Demo4_TrainTicketsCase();
new Thread(ticket, "小红").start();
new Thread(ticket, "老师").start();
new Thread(ticket, "黄牛1").start();
new Thread(ticket, "黄牛2").start();
}
}
案例:模拟龟兔赛跑 #
/**
* 模拟龟兔赛跑
*/
public class Demo5_RaceCase implements Runnable {
//胜利者
private static String winner;
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
//模拟兔子休息
if (Thread.currentThread().getName().equals("兔子") && i % 10 == 0) {
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//判断比赛是否结束
boolean flag = gameOver(i);
//如果比赛结束,停止程序
if (flag) {
break;
}
System.out.println(Thread.currentThread().getName() + "--->跑了" + i + "步");
}
}
//判断是否完成
private boolean gameOver(int steps) {
if (winner != null) {
return true;
} else {
if (steps >= 100) {
winner = Thread.currentThread().getName();
System.out.println("winner is " + winner);
return true;
}
}
return false;
}
public static void main(String[] args) {
Demo5_RaceCase race = new Demo5_RaceCase();
new Thread(race, "兔子").start();
new Thread(race, "乌龟").start();
}
}
实现Callable接口(了解) #
- 实现Callable接口,需要返回值类型
- 重写call方法,需要抛出异常
- 创建目标对象
- 创建执行服务:
ExecutorService ser = Executors.newFixedThreadPool(1);
- 提交执行:
Future result1 = ser.submit(callable);
- 获取结果:
boolean r1 = result1.get()
- 关闭服务:
ser.shutdownNow();
实现 #
/**
* 实现Callable接口
*/
public class Demo6_CreateCallable implements Callable<Boolean> {
private String url;//网络图片地址
private String name;//报错扥文件名
//有参构造
public Demo6_CreateCallable(String url, String name) {
this.url = url;
this.name = name;
}
//下载图片线程的执行体
public Boolean call() throws Exception {
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url, name);
System.out.println("下载了文件名为:" + name);
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
Demo6_CreateCallable c = new Demo6_CreateCallable("https://img-home.csdnimg.cn/images/20201124032511.png", "1.png");
Demo6_CreateCallable c1 = new Demo6_CreateCallable("https://img-home.csdnimg.cn/images/20201124032511.png", "2.png");
Demo6_CreateCallable c2 = new Demo6_CreateCallable("https://img-home.csdnimg.cn/images/20201124032511.png", "3.png");
//创建执行服务
ExecutorService ser = Executors.newFixedThreadPool(3);
//提交执行
Future<Boolean> r = ser.submit(c);
Future<Boolean> r1 = ser.submit(c1);
Future<Boolean> r2 = ser.submit(c2);
//获取结果
boolean res = r.get();
boolean res1 = r1.get();
boolean res2 = r2.get();
//关闭服务
ser.shutdownNow();
}
}
//class WebDownloader在前面下载图片已经定义了,这里就不用再次写,直接使用就好
好处 #
可以定义返回值。可以抛出异常
Thread和Runnable对比 #
继承Thred类: 子类继承Thread类具备多线程能力
- 启动线程:子类对象.start()
- 不建议使用:避免OOP单继承局限性
实现Runnable接口
- 实现接口Runnable具有多线程能力
- 启动线程:传入目标对象+Thread对象.start()
- 推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用
静态代理 #
- Thread类实际上实现了 Runnable接口,而我们也要实现Runnable接口,实际上Thread类就是代理我们类扩展了一些额外的功能。
- 真实对象和代理对象都要实现一个接口。代理对象要代理真实角色
- 代理对象可以做很多真实对象做不了的事情。真实对象专注做自己的事
/**
* 静态代理:结婚案例
*/
public class Demo7_StaticProxy {
public static void main(String[] args) {
new WeddingCompany(new You()).happyMarry();
//实际上和
//new Thread(new CreateRunnable()).start();
//是一样的,也可以写成Lambda表达式
}
}
//结婚
interface Marry {
void happyMarry();
}
//真实角色:你去结婚
class You implements Marry {
@Override
public void happyMarry() {
System.out.println("doris要结婚了,超开心");
}
}
//代理角色:帮助你结婚
class WeddingCompany implements Marry {
private Marry target;//代理-->真实目标角色角色,帮谁结婚
public WeddingCompany(Marry target) {
this.target = target;
}
@Override
public void happyMarry() {
after();
this.target.happyMarry();
before();
}
private void after() {
System.out.println("结婚之前,布置现场");
}
private void before() {
System.out.println("结婚之后,收尾款");
}
}