多线程问题,求帮助。

刘胤杰 2019-06-10 08:55:42
多线程问题,为什么sellTicket01方法加锁失败?
题目是: 使用线程模拟火车站多窗口售票。
基本解决思路是,票篮对象作为临界资源,三个线程通过加锁进行互斥访问。
互斥访问用同步控制块、同步方法两种方式。
用同步控制块可以实现互斥访问。但用同步方法(即:sellTicket01())却不行。
代码见下面,请各位大侠指点迷津!

btw:Runnable的实现类的方式我用过。这次就想用继承Thread方式来解决。

---------------------------------------------------------------------------------------
package cn.sit;

import java.util.Random;

/**
* 使用线程模拟火车站多窗口售票。 1.火车站有多个售票窗口 2.多售票窗口共用一个统一票篮
*
* @author Y.J.Liu
*
*/
//共用的票篮
class TicketsBasket {
private int ticketNumber;// 现存车票数量

public TicketsBasket() {// 构造方法,车票初始值为20
this.ticketNumber = 20;
}

public int getTicketNumber() {
return ticketNumber;
}

public synchronized void decreaseTicketNumber() {// 卖出一张车票,现存车票数量减一
this.ticketNumber--;
}
}

//------------------------------------------------------------
class Web12306 extends Thread {
private TicketsBasket ticketsBasket;
private boolean flag = true;

/**
* 构造方法
* @param ticketsBasket 公用的票篮
* @param name 线程名称,及售票站名称
*/
public Web12306(TicketsBasket ticketsBasket, String name) {
super(name);
this.ticketsBasket = ticketsBasket;
}

@Override
public void run() {
Random random = new Random();

while (flag) {
try {
Thread.sleep(random.nextInt(20));
} catch (InterruptedException e) { }
sellTicket01();//售票方法
}
}
//---------------------------------------------------------------
//售票方法01
private synchronized void sellTicket01() {
if (ticketsBasket.getTicketNumber() <= 0) {
flag = false;// 如果车票数小于等于0,退出线程
return;
}
// 售出车票
System.out.println(Thread.currentThread().getName() + "售出" + ticketsBasket.getTicketNumber() + "号车票。");
// 未售出车票数减1
ticketsBasket.decreaseTicketNumber();
}
//----------------------------------------------------------------
//售票方法02
private void sellTicket02() {
synchronized (ticketsBasket) {
if (ticketsBasket.getTicketNumber() <= 0) {
flag = false;// 如果车票数小于等于0,退出线程
return;
}
// 售出车票
System.out.println(Thread.currentThread().getName() + "售出" + ticketsBasket.getTicketNumber() + "号车票。");
// 未售出车票数减1
ticketsBasket.decreaseTicketNumber();
}

}

}

//----------------测试类---------------------------------------
public class SellTicketDemo01 {

public static void main(String[] args) {
TicketsBasket ticket12306 = new TicketsBasket();
Web12306 station01 = new Web12306(ticket12306, "xuhui");
Web12306 station02 = new Web12306(ticket12306, "fengxian");
Web12306 station03 = new Web12306(ticket12306, "新客站");
station01.start();
station02.start();
station03.start();
}
}
...全文
163 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq_39936465 2019-06-11
  • 打赏
  • 举报
回复
帮你用你的方法改了一下

import java.util.Random;

public class test8 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		TicketsBasket ticket12306 = new TicketsBasket();
		Web12306 station01 = new Web12306(ticket12306, "xuhui");
		Web12306 station02 = new Web12306(ticket12306, "fengxian");
		Web12306 station03 = new Web12306(ticket12306, "新客站");
		station01.start();
		station02.start();
		station03.start();
	}
}

class TicketsBasket {
	private int ticketNumber;// 现存车票数量

	public TicketsBasket() {// 构造方法,车票初始值为20
		this.ticketNumber = 20;
	}

	public int getTicketNumber() {
		return ticketNumber;
	}

	public void decrease() {// 卖出一张车票,现存车票数量减一
		this.ticketNumber--;
	}

	public synchronized void sellTicket01() {
		if (ticketNumber > 0) {
			// 售出车票
			System.out.println(Thread.currentThread().getName() + "售出" + getTicketNumber() + "号车票。");
			// 未售出车票数减1
			decrease();
		}
	}
}

class Web12306 extends Thread {
	TicketsBasket ticketsBasket = null;

	/**
	 * @param tb
	 */
	public Web12306(TicketsBasket ticketsBasket, String name) {
		super(name);
		this.ticketsBasket = ticketsBasket;
	}

	@Override
	public void run() {
		Random random = new Random();

		while (ticketsBasket.getTicketNumber() > 0) {
			try {
				Thread.sleep(random.nextInt(20));
				ticketsBasket.sellTicket01();// 售票方法
			} catch (InterruptedException e) {
			}

		}
	}
}

qq_39936465 2019-06-11
  • 打赏
  • 举报
回复
你把sell方法放入catch里,只有程序异常才会执行,你的程序什么时候才会异常? 买票是异常情况?!
qq_39936465 2019-06-11
  • 打赏
  • 举报
回复
引用 楼主 刘胤杰 的回复:
多线程问题,为什么sellTicket01方法加锁失败? 题目是: 使用线程模拟火车站多窗口售票。 基本解决思路是,票篮对象作为临界资源,三个线程通过加锁进行互斥访问。 互斥访问用同步控制块、同步方法两种方式。 用同步控制块可以实现互斥访问。但用同步方法(即:sellTicket01())却不行。 代码见下面,请各位大侠指点迷津!
只是买票不用这么复杂

public class test7 implements Runnable {
	int ticket = 20;

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (ticket > 0) {
			synchronized (this) {
				if(ticket>0) {
					System.out.println(Thread.currentThread().getName() + "售出" + (21 - ticket) + "号车票。");
					ticket--;
				}	
			}
		}
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		test7 t1 = new test7();
		Thread td1 = new Thread(t1, "xuhui");
		Thread td2 = new Thread(t1, "fengxian");
		Thread td3 = new Thread(t1, "新客站");
		td1.start();
		td2.start();
		td3.start();
	}

}
刘胤杰 2019-06-11
  • 打赏
  • 举报
回复
引用 8 楼 qq_39936465 的回复:
[quote=引用 7 楼 刘胤杰 的回复:]
多谢!
还有一事不明,57行也访问了ticketNumber,为什么不需要synchronized?谢谢!


57行主要是为了判断循环执行,主要数据的同步靠sell方法中有if来判断,while的数据不同步并不影响买票过程,所以不需要做到这么准确。[/quote]

受教了,多谢!
qq_39936465 2019-06-11
  • 打赏
  • 举报
回复
引用 7 楼 刘胤杰 的回复:
多谢! 还有一事不明,57行也访问了ticketNumber,为什么不需要synchronized?谢谢!
57行主要是为了判断循环执行,主要数据的同步靠sell方法中有if来判断,while的数据不同步并不影响买票过程,所以不需要做到这么准确。
刘胤杰 2019-06-11
  • 打赏
  • 举报
回复
引用 6 楼 qq_39936465 的回复:
帮你用你的方法改了一下


import java.util.Random;

public class test8 {

public static void main(String[] args) {
// TODO Auto-generated method stub
TicketsBasket ticket12306 = new TicketsBasket();
Web12306 station01 = new Web12306(ticket12306, "xuhui");
Web12306 station02 = new Web12306(ticket12306, "fengxian");
Web12306 station03 = new Web12306(ticket12306, "新客站");
station01.start();
station02.start();
station03.start();
}
}

class TicketsBasket {
private int ticketNumber;// 现存车票数量

public TicketsBasket() {// 构造方法,车票初始值为20
this.ticketNumber = 20;
}

public int getTicketNumber() {
return ticketNumber;
}

public void decrease() {// 卖出一张车票,现存车票数量减一
this.ticketNumber--;
}

public synchronized void sellTicket01() {
if (ticketNumber > 0) {
// 售出车票
System.out.println(Thread.currentThread().getName() + "售出" + getTicketNumber() + "号车票。");
// 未售出车票数减1
decrease();
}
}
}

class Web12306 extends Thread {
TicketsBasket ticketsBasket = null;

/**
* @param tb
*/
public Web12306(TicketsBasket ticketsBasket, String name) {
super(name);
this.ticketsBasket = ticketsBasket;
}

@Override
public void run() {
Random random = new Random();

while (ticketsBasket.getTicketNumber() > 0) {
try {
Thread.sleep(random.nextInt(20));
ticketsBasket.sellTicket01();// 售票方法
} catch (InterruptedException e) {
}

}
}
}




多谢!
还有一事不明,57行也访问了ticketNumber,为什么不需要synchronized?谢谢!

62,612

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧