(一)实验目的
1、掌握JAVA中多线程的实现方法;
2、重点掌握多线程的同步与通信机制;
3、熟悉JAVA中有关多线程同步与通信的方法 ;
4、能使用多线程机制解决实际应用中的线程同步与通信问题。
(二)实验内容和步骤
1、在线售票系统
现有一个在线售票系统,总共有200张票,假设同时有5个人同时在线订票,网络传输延时为3毫秒,试编写程序模拟售票过程。要求分别使用 同步代码块
与 同步方法
实现。
进阶设计:当有人订票的数量达到10张后则退出订票系统
💖 TicketSystem.java
public class TicketSystem
{
private volatile int tickets = 200; // 总票数
private volatile boolean finished = false;
public static void main(String[] args)
{
TicketSystem ticketSystem = new TicketSystem();
ticketSystem.bookTickets();
}
// 使用同步代码块实现订票
public void bookTicketSyncBlock()
{
synchronized (this)
{
if (finished)
return;
if (tickets > 0)
{
tickets--;
System.out.println(Thread.currentThread().getName() + "订到了一张票,剩余票数:" + tickets);
} else
{
System.out.println("票已售罄。");
}
}
}
// 使用同步方法实现订票
public synchronized boolean bookTicketSyncMethod()
{
if (finished)
return false;
if (tickets > 0)
{
tickets--;
System.out.println(Thread.currentThread().getName() + "订到了一张票,剩余票数:" + tickets);
return true;
} else
{
System.out.println("票已售罄");
return false;
}
}
// 模拟订票过程
public void bookTickets()
{
Thread[] threads = new Thread[5];
for (int i = 0; i < threads.length; i++)
{
threads[i] = new Thread(() -> {
for (int j = 0; j < 10; j++)
{ // 每个线程尝试订票10次
synchronized (this)
{
bookTicketSyncBlock(); // 或者使用 bookTicketSyncMethod() 来代替 bookTicketSyncBlock()
// bookTicketSyncMethod();
if (j == 9)// 某个线程抢到了 10 张票,购票系统关闭
finished = true;
}
try
{
Thread.sleep(30);// 模拟网络延迟 3 毫秒
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, "Thread-" + (i + 1));
}
for (int i = 0; i < 5; i++)
threads[i].start();
}
}
💖 运行结果
Thread-1订到了一张票,剩余票数:199
Thread-5订到了一张票,剩余票数:198
Thread-4订到了一张票,剩余票数:197
Thread-3订到了一张票,剩余票数:196
Thread-2订到了一张票,剩余票数:195
Thread-5订到了一张票,剩余票数:194
Thread-2订到了一张票,剩余票数:193
Thread-1订到了一张票,剩余票数:192
Thread-3订到了一张票,剩余票数:191
Thread-4订到了一张票,剩余票数:190
Thread-2订到了一张票,剩余票数:189
Thread-5订到了一张票,剩余票数:188
Thread-4订到了一张票,剩余票数:187
Thread-1订到了一张票,剩余票数:186
Thread-3订到了一张票,剩余票数:185
Thread-4订到了一张票,剩余票数:184
Thread-1订到了一张票,剩余票数:183
Thread-3订到了一张票,剩余票数:182
Thread-2订到了一张票,剩余票数:181
Thread-5订到了一张票,剩余票数:180
Thread-5订到了一张票,剩余票数:179
Thread-3订到了一张票,剩余票数:178
Thread-1订到了一张票,剩余票数:177
Thread-2订到了一张票,剩余票数:176
Thread-4订到了一张票,剩余票数:175
Thread-4订到了一张票,剩余票数:174
Thread-3订到了一张票,剩余票数:173
Thread-5订到了一张票,剩余票数:172
Thread-1订到了一张票,剩余票数:171
Thread-2订到了一张票,剩余票数:170
Thread-5订到了一张票,剩余票数:169
Thread-2订到了一张票,剩余票数:168
Thread-4订到了一张票,剩余票数:167
Thread-1订到了一张票,剩余票数:166
Thread-3订到了一张票,剩余票数:165
Thread-1订到了一张票,剩余票数:164
Thread-5订到了一张票,剩余票数:163
Thread-4订到了一张票,剩余票数:162
Thread-2订到了一张票,剩余票数:161
Thread-3订到了一张票,剩余票数:160
Thread-2订到了一张票,剩余票数:159
Thread-3订到了一张票,剩余票数:158
Thread-4订到了一张票,剩余票数:157
Thread-5订到了一张票,剩余票数:156
Thread-1订到了一张票,剩余票数:155
Thread-1订到了一张票,剩余票数:154
2、坦克大战
在坦克大战游戏当中,我方坦克和敌方坦克均可以发射炮弹。现只考虑我方坦克发射炮弹的情况,在没有升级前,我方坦克发射的炮弹只有在碰到敌方坦克、障碍物爆炸或越过边界后(可以使用线程休眠一定时间来模拟)才能发射下一发炮弹。请编写程序模拟我方坦克发射炮弹的过程。
💖 Game.java
public class Game
{
public static void main(String[] args)
{
Tank friendlyTank = new Tank("我方坦克");
// 模拟我方坦克连续发射炮弹
for (int i = 0; i < 5; i++)
{
friendlyTank.fireBullet();
try
{
Thread.sleep(5000); // 模拟炮弹发射间隔时间
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
static class Tank
{
private String name;
public Tank(String name)
{
this.name = name;
}
public void fireBullet()
{
System.out.println(name + " 发射了一发炮弹!");
new Bullet(this).start(); // 创建一个线程来模拟炮弹的移动
}
}
static class Bullet extends Thread
{
private Tank tank;
public Bullet(Tank tank)
{
this.tank = tank;
}
@Override
public void run()
{
try
{
// 模拟炮弹飞行时间
Thread.sleep(2000); // 假设炮弹飞行2秒
System.out.println(tank.name + " 的炮弹飞行了2秒后爆炸了!");
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}