1.理论知识
总所周知创建多线程到底有多少种方法一直引起很大的争议、有人说三种、还有说四种、甚至还有两种、今天新手村程序员告诉大家我也不知道到底说几种是对的、但是!! 学到自己手里才是最重要的今天我列举最常用的三种方法
1.2 三种方法
1.继承 Thread 类 重写run()方法 并调用 start() 方法。
2.实现Runnable 接口 重写run()方法 并调用 start() 方法。
3.实现 Callable 接口并通过 ExecutorService 创建一个新的类实现 Callable 接口,并实现 call() 方法。使用 ExecutorService 提交 Callable 任务,并获取 Future 对象来获取异步计算的结果。
1.3 如何选择
怎么多种方法该如何选择呢、如果你的类不需要继承父类的话可以选择第一种方法、因为Java是单继承第一种方法就会占用这个类的继承、当然如果有继承需求的话就可以使用第二种方法、这时候需求又来了如果我又想要继承父类又想要返回值该怎么办呢、这时候就可以用到第三种方法
2.真实需求
这时候甲方的需求来了
甲方:啊 小X 啊 我要做一个网上售票网站 然后让他们能在我这买票就好了
没错描述的就是这么简单 那我们就开始做
2.1 第一版
很快就完成了 我们现在给它命名为 ShouPiao 1.0
package com.theone;
import java.util.Scanner;
public class ShouPiao {
//票余量
private static Integer piao = 100;
public static void main(String[] args) {
//开启输入
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("请输入购买数量当前票数:"+piao);
//购买数量
int num = scanner.nextInt();
//如果票数大于购买数量即票数充足
if (piao >= num) {
piao -= num;
System.out.println("购买成功当前余票:" + piao);
}else {
System.out.println("购票失败 原因余票不足");
}
}
}
}
我们来测试一下
效果很好 那么这个代码有没有问题呢? 当然有问题 如果这时候哪位大佬用了非正常手段输入了 中文的数字 比如说 那么程序就会崩溃
这时候我们来改进一下代码 可以使用try catch 包裹 或者 throw 抛出异常 这里我使用 第一种方法
2.2 第二版
package com.theone;
import java.util.Scanner;
public class ShouPiao {
//票余量
private static Integer piao = 100;
public static void main(String[] args) {
//开启输入
Scanner scanner = new Scanner(System.in);
while (true) {
try {
System.out.println("请输入购买数量当前票数:" + piao);
//购买数量
int num = scanner.nextInt();
//如果票数大于购买数量即票数充足
if (piao >= num) {
piao -= num;
System.out.println("购买成功当前余票:" + piao);
} else {
System.out.println("购票失败 原因余票不足");
}
} catch (Exception e) {
System.out.println("错误 请输入 阿拉伯数字");
//忽略错误的输入 开启下一次输入
scanner.next();
}
}
}
}
运行效果展示
但是 如果这个系统做出来是单线程的那么在同一时间只有一个售票员能卖票 如果要多个售票员可以同时卖票的话就会用到多线程 我们继续改进一下
2.3 第三版
我使用到了 Lock 加锁
Condition 我使用了它的两个方法
await() 方法让当前线程等待,直到被其他线程唤醒。
signal() 方法唤醒一个等待的线程。
package com.theone;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class ShouPiao implements Runnable{
//锁
private static final Lock lock = new ReentrantLock();
//线程
private static final Condition condition = lock.newCondition();
//票
private static int piao = 100;
@Override
public void run() {
while (true) {
try {
//获取锁
lock.lock();
//如果票数大于购买数量即票数充足
if (piao > 0) {
try {
//模拟购票操作的延迟 睡眠 100毫秒
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//输出余票
System.out.println(Thread.currentThread().getName()+"购买成功当前余票:" + (101-piao));
piao --;
//唤醒其他等待的进程
condition.signal();
//当前线程进入等待状态
condition.await();
}
} catch (Exception e) {
throw new RuntimeException(e);
}finally {
//释放锁
lock.unlock();
}
}
}
public static class main{
public static void main(String[] args) {
//开启多线程
ShouPiao shouPiao = new ShouPiao();
//创建多线程
Thread window1 = new Thread(shouPiao,"一号售票处");
window1.start();
Thread window2 = new Thread(shouPiao,"二号售票处");
window2.start();
}
}
}
运行效果 这样就实现了多线程的方法 两个售票员交替卖票互不干预
3.知识点总结
try-catch 的使用时机
创建线程的多种方式
如何加锁