1.卖票练习
@Slf4j
public class ExerciseSell {
public static void main(String[] args) throws InterruptedException {
//模拟多人买票
TicketWindows ticketWindows = new TicketWindows(1000);
//所有线程的集合
List<Thread> threads = new ArrayList<>();
//卖出的票数统计
List<Integer> amountList = new Vector<>();
for (int i = 0; i < 2000; i++) {
Thread thread = new Thread(() -> {
//买票
int amount = ticketWindows.sell(random(5));
try {
Thread.sleep(random(500));
} catch (InterruptedException e) {
e.printStackTrace();
}
//统计买票数
amountList.add(amount);
});
threads.add(thread);
thread.start();
}
for (Thread thread : threads) {
thread.join();
}
//统计卖出的票数和剩余的票数
log.debug("余票:{}", ticketWindows.getCount());
log.debug("卖出的票:{}", amountList.stream().mapToInt(i -> i).sum());
}
//Random为线程安全
static Random random = new Random();
//随机1~5
public static int random(int amount) {
return random.nextInt(amount) + 1;
}
}
//售票窗口
class TicketWindows {
private int count;
public TicketWindows(int count) {
this.count = count;
}
//获取余票数量
public int getCount() {
return count;
}
//售票
public synchronized int sell(int amount) {
if (this.count >= amount) {
this.count -= amount;
return amount;
} else {
return 0;
}
}
}
2.转账练习
@Slf4j
public class Test1 {
public static void main(String[] args) throws InterruptedException {
Account a = new Account(1000);
Account b = new Account(1000);
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
a.transfer(b, randomAccount());
}
}, "t1");
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
b.transfer(a, randomAccount());
}
}, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
//查看转账2000次后的总余额
log.debug("总余额:{}", a.getMoney() + b.getMoney());
}
//Random为线程安全的
static Random random = new Random();
//随机1~100
public static int randomAccount() {
return random.nextInt(100) + 1;
}
}
class Account {
private int money;
public Account(int money) {
this.money = money;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
public void transfer(Account target, int amount) {
//这样写肯定是线程不安全的,所以应该同时将账户a和账户b的money同时加锁
// 但对两个对象的成员变量加不同的锁依然解决不了线程安全问题
//通过分析可以发现this.money和target.money又同时共享了Account类
synchronized (Account.class) {
if (this.money >= amount) {
this.setMoney(this.getMoney() - amount);
target.setMoney(target.getMoney() + amount);
}
}
}
// public void transfer(Account target, int amount) {
// //这样写肯定是线程不安全的,所以应该同时将账户a和账户b的money同时加锁
// //但对两个对象的成员变量加不同的锁依然解决不了线程安全问题
// synchronized (this) {
// if (this.money >= amount) {
// this.setMoney(this.getMoney() - amount);
// target.setMoney(target.getMoney() + amount);
// }
// }
// }