实验内容
编写java程序,使用Thread 类或Runnable接口创建子线程,实现一个多窗口售票问题。A、B两个窗口同时对共享的10张票进行售卖。
要求:
1)说明java的线程创建语句;
2)分析问题中的临界资源,对比采用和不采用线程锁(synchronized) 实现互斥的共享时运行的结果的区别,并说明原因。3)每个线程在售票后输出格式为“时间+售卖出第i张票”,售票后通过sleep()函数使线程进入阻塞,并截图说明sleep()函数在不同参数下执行的变化。
基础知识简介
线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。
synchronized的使用很简单,可以用它来修饰实例方法和静态方法,也可以用来修饰代码块。synchronized是一个对象锁,也就是它锁的是一个对象。用它锁住对象,避免多个线程对临界资源这个对象进行访问,防止发生并发带来的冲突问题。
希望更深入学习synchronized关键字的,可以参考以下链接:Java中Synchronized的用法(简单介绍)
实验过程
使用两个窗口对票进行售卖,其中一个使用线程锁,一个不使用,对比观察输出结果。
首先线程创建语句创建Thread对象,随后TicketSeller类使用Runnable接口,重写方法run。采用线程锁和不采用线程锁的输出结果不同,采用线程锁后正常对票进行售卖,不采用线程锁则会发生票重复售出的情况。
发生原因为:当一个线程访问一个被synchronized关键字保护的代码块或方法时,会尝试获取该对象的锁,如果锁没有被其他线程占用,则该线程获取锁并执行代码;如果锁已经被其他线程占用,则该线程会被阻塞,直到其他线程释放锁,以此保护临界资源被多个线程读取。
当sleep(1000)时,线程会在售票后阻塞1秒钟,然后继续执行;当sleep(5000)时,线程会在售票后阻塞5秒钟,然后继续执行。
代码
public class TicketSeller implements Runnable{
private int ticket = 10;
@Override
public void run() {
while (ticket > 0) {
synchronized (this) {//线程锁
if (ticket > 0) {//对票进行售卖
System.out.println(System.currentTimeMillis() + " 售卖出第" + (11 - ticket) + "张票");//展示售票时间和售卖的票数
ticket--;
}
}
try {
Thread.sleep(50); // 售票后进入阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
TicketSeller seller = new TicketSeller();
Thread t1 = new Thread(seller);
Thread t2 = new Thread(seller);
t1.start();
t2.start();
}
}
public class TicketSeller2 implements Runnable {
private volatile int ticket = 10;
@Override
public void run() {
while (ticket > 0) {
if(ticket > 0){
System.out.println(System.currentTimeMillis() + " 售卖出第" + (11 - ticket) + "张票");
ticket --;
}else{
break;
}
try {
Thread.sleep(50); // 售票后进入阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
TicketSeller2 seller = new TicketSeller2();
Thread t1 = new Thread(seller);
Thread t2 = new Thread(seller);
t1.start();
t2.start();
}
}
谢谢各位的阅读