1. 卖票
利用 Runnable
接口的实现类定义多个线程所要共同完成的任务(数据作为成员变量实现共享),继承Thread类的方法太笨重,继承了一堆用不着的东西。
public class Ticket implements Runnable {
private int counter = 100; //100张票作为共享数据
private Lock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
// 把共享数据锁住。
lock.lock();
// if (counter > 0) {
//
// try {
// Thread.currentThread().sleep(10);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
//
// System.out.println(Thread.currentThread().getName() +
// "卖出第 " + (counter--) + " 张票");
// lock.unlock();
// } else {
//// 这样写可能仍然有风险,释放锁之后,就有可能被打断了。
// lock.unlock();
// break;
// }
// 利用finally实现break语句之后还可以执行操作!
try {
if (counter > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() +
"卖出第 " + (counter--) + " 张票");
} else {
break;
}
} finally {
lock.unlock();
}
}
}
}
注意:
while(true) {
lock.lock();
if (counter > 0) {}
}
不能修改为:
lock.lock();
while(counter > 0) {}
因为把while语句锁住了,某个线程就会一直执行下去。
客户端:
public class SellTicket {
public static void main(String[] args) {
Ticket ticket = new Ticket();
Thread t1 = new Thread(ticket, "窗口1");
Thread t2 = new Thread(ticket, "窗口2");
t1.start();
t2.start();
// 不想写类,就可以全部使用匿名内部类实现
}
}
2. 抽奖
证明线程的栈是私有的,也就是run方法里面的局部变量是线程私有的。这意味着局部变量之间并不会互相干扰,没有安全问题。意识到这一点可以简化代码,增加代码的灵活性,不用写死。
弱鸡版(代码有一部分是写死的):
public class Lottery implements Runnable {
private ArrayList<Integer> pool; //奖池
private Random random;
private Lock lock = new ReentrantLock();
private ArrayList<Integer> box1; //线程1抽到的奖品
private ArrayList<Integer> box2; //线程2抽到的奖品
public Lottery(ArrayList<Integer> pool) {
this.pool = pool;
this.random = new Random();
this.box1 = new ArrayList<>();
this.box2 = new ArrayList<>();
}
@Override
public void run() {
while (true) {
lock.lock();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
if (pool.size() > 0) {
int index = random.nextInt(pool.size());
int money = pool.remove(index);
// 代码是写死的,抽奖箱换名字怎么办。
if (Thread.currentThread().getName().equals("抽奖箱1")) {
box1.add(money);
} else {
box2.add(money);
}
} else {
if (Thread.currentThread().getName().equals("抽奖箱1")) {
printBox(box1);
} else {
printBox(box2);
}
break;
}
} finally {
lock.unlock();
}
}
}
private static void printBox(ArrayList<Integer> box) {
System.out.println("在此次抽奖过程中," + Thread.currentThread().getName() +
"总共产生了" + box.size() + "个奖项,分别为:" + box);
if (box.size() != 0) {
System.out.println("最高奖项为:" + Collections.max(box) + "。 总计为:");
}
}
}
升级版:
public class Lottery implements Runnable {
private ArrayList<Integer> pool;
private Random random;
private Lock lock = new ReentrantLock();
public Lottery(ArrayList<Integer> pool) {
this.pool = pool;
this.random = new Random();
}
@Override
public void run() {
// 局部变量为线程私有,每个线程都会在堆中创建一个自己的box
ArrayList<Integer> box = new ArrayList<>();
while (true) {
lock.lock();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
if (pool.size() > 0) {
int index = random.nextInt(pool.size());
int money = pool.remove(index);
box.add(money);
} else {
printBox(box);
break;
}
} finally {
lock.unlock();
}
}
}
private static void printBox(ArrayList<Integer> box) {
System.out.println("在此次抽奖过程中," + Thread.currentThread().getName() +
"总共产生了" + box.size() + "个奖项,分别为:" + box);
if (box.size() != 0) {
System.out.println("最高奖项为:" + Collections.max(box) + "。 总计为:");
}
}
}
客户端:
public class LotteryTest {
public static void main(String[] args) {
ArrayList<Integer> arr = new ArrayList<>();
// 得到一个不可修改的List,无法对其进行增删操作。
List<Integer> list = List.of(10,5,20,50,100,200,500,800,2,80,300,700);
arr.addAll(list);
// 也可以这样批量添加
// Integer[] arr1 = {10,5,20,50,100,200,500,800,2,80,300,700};
// 把可变参数作为数组传入
// Collections.addAll(arr, arr1);
Lottery lottery = new Lottery(arr);
new Thread(lottery, "抽奖箱1").start();
new Thread(lottery, "抽奖箱2").start();
}
}
网友评论