java线程分析:利用售票机例子分析线程运行状态

线程运行往往不尽人意

问题:一共有四个售票机,总票数为100.设计程序用多线程解决问题.每个线程代表一个售票机.
乍一看感觉这个题目非常简单,只要设计四个线程,每个线程用while执行,在while中加上线程锁,就可以解决问题.

这是启动程序:
主要功能是建立Thread对象,然后设置四个线程,同时执行售票程序.

这是启动程序:
主要功能是建立Thread对象,然后设置四个线程,同时执行售票程序.
package package_1;

public class Main_Thread {

	public static void main(String[] args) {
		Ticket_Thread st = new Ticket_Thread();
		Thread t1 = new Thread(st, "售票机一号");
		Thread t2 = new Thread(st, "售票机二号");
		Thread t3 = new Thread(st, "售票机三号");
		Thread t4 = new Thread(st, "售票机四号");
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}
这是子程序:
package package_1;

public class Ticket_Thread implements Runnable {
	private int count = 1;
	private Object lock = new Object();

	@Override
	public void run() {
		Thread thisThread = Thread.currentThread();
		while (count <= 100) {
			synchronized (lock) {
				System.out.println("本次为您服务的是" + thisThread.getName() + "售票机:");
				System.out.println("已出售" + count + "张,剩余:" + (100 - count) + "张");
				count++;
			}
		}
	}
}

我们预计的结果是每条线程随机分配执行,当count = 100的时候,循环条件被打破,各个子线程执行完毕,同时主线程也执行完毕.

以上代码的执行结果:

在这里插入图片描述

预期和结果不符,为什么售票数会显示-1~-3呢?

先让我们来看一下线程执行的流程图(图片)

在这里插入图片描述
从start开始,等分配到了cpu资源之后,每一条线程就开始执行自己的run()了,当在run()中遇到synchronized()时,每条线程进入
等待状态(等待池),随机获得锁.当synchronized块执行完毕之后,归还锁.如果满足循环条件,循环继续.

猜想1:问题主要出在最后几个结果.我们设置用count来记录次数,当count = 10的时候,while循环结束.由于synchronized是包含在while中的,如果当每个线程同时执行(时间差为0)的时候,理论上每个线程在执行完synchronized(获取锁,归还锁)之后会同步执行.
对于我们的程序来,当count = 10时,所有线程进入while循环,继续往下执行,遇到synchronized,其中一条线程拿到锁,继续执行,其他线程进入等锁池.当这条线程执行完synchronized块之后 归还锁,使得count++,这时候count = 11,这一条线程条件不符合,循环结束.
但是其它三条线程已经处于while中,无法在此时判断条件,所以继续随机获得锁,继续执行.由此类推,可以得出当线程1执行了count++,使count = 11之后,其余个线程还要执行一次synchronized中的代码.最后使得售票数量为-3,此时的count应该为13.
我们可以验证一下,在执行完循环之后,输出count


到这里问题似乎解决了,但加上加上Thread.sleep()之后,结果却变成了这样:

设置休眠1毫秒
	public void run() {
		Thread thisThread = Thread.currentThread();
		while (count <= 100) {
			synchronized (lock) {
				System.out.println("本次为您服务的是" + thisThread.getName() + "售票机:");
				System.out.println("已出售" + count + "张,剩余:" + (100 - count) + "张");
				count++;
			}
			try {
				Thread.sleep(0);	
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
设置休眠10毫秒:

按照我们刚刚的猜想,如果每个线程正常运行的话,结果都应该使 -3 才对,可为什么当线程休眠了1毫秒的时候会出现那么多结果呢?

原来每个线程交替执行,cpu的交替调用也是需要时间的.count自增需要时间,归还锁需要时间,while()条件的判断也是需要时间的,总的来说,各种操作都需要花费时间.当线程1比线程2多执行一次,那么完成自增的count = 11的时候,线程2就有可能还是处于休眠状态时,当此线程休眠结束,再次判断循环条件的时候,count已经等于11了,循环终止,count也就不再自增了,如果不处于休眠状态的时候,说明已经进入while循环,这时候count还是会自增.这取决于线程交替调用的时间消耗.时间消耗大于另一条线程的休眠时间时,便会进入下一个循环.由于计算机每次执行所消耗的时间不同,得出的结论也会有所不同.

为了验证这一点,我们把交替次数减少,让休眠时间增加.

	public void run() {
		Thread thisThread = Thread.currentThread();
		while (count <= 10) {
			synchronized (lock) {
				System.out.println("本次为您服务的是" + thisThread.getName() + "售票机:");
				System.out.println("已出售" + count + "张,剩余:" + (10 - count) + "张");
				count++;
			}
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

这时候结果为:
在这里插入图片描述
简单分析一下,我们使得每次交替的时间小于休眠的时间,使得每次循环的时候,每条线程都会执行一次.最后得出结果为-2.

当然不让负票数出现的另一个方法,也是很简单的方法就是:

	public void run() {
		Thread thisThread = Thread.currentThread();
		while (count <= 100) {
			synchronized (lock) {
				if (count == 101) {
					System.out.println(thisThread.getName() + ":已售完!!");
					break;
				}
				System.out.println("本次为您服务的是" + thisThread.getName() + "售票机:");
				System.out.println("已出售" + count + "张,剩余:" + (100 - count) + "张");
			}
			System.out.println("count:" + count);
		}
	}

在synchronized块中加一个分支条件判断呗~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值