利用实现Runnable接口 实现多线程
// 原由:当资源(java类)作为多个线程共有的资源
// 结论:将此类情况的java类定义为Runnable接口的实现类,以供多个线程共同特有
public class Thread03 {
public static void main(String[] args) {
// ③ 创建实现体对象
Ticket ticket = new Ticket();
// ④ 为实现体对象分配线程
Thread t1 = new Thread(ticket, "一号窗口");
Thread t2 = new Thread(ticket, "二号窗口");
Thread t3 = new Thread(ticket, "三号窗口");
// ⑤ 开启线程
t1.start();
t2.start();
t3.start();
}
}
// ① 实现Runnable接口
public class Ticket implements Runnable{
//定义互斥锁
private static final Object mutex = new Object();
private int num;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public Ticket() {
this.num = 20;
}
// ② 实现run方法
@Override
public void run() {
// 卖票
// sellTickets();
sellTicketSuper();
}
// 卖票
// synchronized 同步锁
// ① synchronized作为方法的关键词
// i)该方法为同步方法:
// 目的:方法同一时刻只能被一个线程锁调用
// 应用场景:方法功能单一,且方法需整体做同步处理
private synchronized void sellTickets() {
while (num > 0) {
// 当前线程名(卖票的窗口号)
String ctName = Thread.currentThread().getName();
// 窗口所卖的票次
int index = 20 - num + 1;
System.out.println(ctName + "抢到第" + index + "张");
// 卖出一张,票据减一张,结果为剩余票数
num--;
System.out.println(ctName + "卖出一张票,剩余票数: "+ num);
}
}
// ② synchronized作为同步代码块
// i) 代码块为同步代码块
// 目的:方法同一时刻只能被一个线程使用
// 应用场景:方法功能逻辑较多,且方法需局部做同步处理
private void sellTicketSuper() {
// 静态代码块synchronized (mutex)
// 参数mutex: 唯一的任意对象
// 通常互斥锁标识:
// static方法中:当前类.class(Ticket.class) 的Class对象
// 成员方法:this
// this不唯一时:static final Object
while (true) {
// 一票一锁:抢到票,可以卖票,买了抢到的那张后就会开锁
synchronized (mutex) {// 加锁的开始
if (num > 0) {
// 当前线程名(卖票的窗口号)
String ctName = Thread.currentThread().getName();
// 窗口所卖的票次
int index = 20 - num + 1;
System.out.println(ctName + "抢到第" + index + "张");
// 卖出一张,票据减一张,结果为剩余票数
num--;
// System.out.println(ctName + "卖出一张票,剩余票数: "+ num);
}
}// 开锁的标识
// 结束卖票判断
if (num <= 0)
break;
Thread.yield();
}
// 锁住的逻辑较多时,可能在执行过程中多次让出CPU执行权,导致其竞争对手
// 在未解锁状态去竞争资源从而进入锁池状态,失去下一次CPU第一时刻竞争权
// 所有需要开锁的线程在开锁后 <强行让出CPU执行权>
// 注:锁池状态的线程在开锁后会重新进入,就绪状态
}
}