在上一篇文章中写到了许多线程共享同一数据,这种情况在现实的生活中也是经常发生的,比如火车站的火车票售票系统。火车票售票系统是一个常年运行的系统,为了满足乘客的需求,我们不能只设一个窗口,必须设很多的售票窗口,每个售票窗口就像一个线程,它们各自运行,共同访问相同的数据——火车票的数量,下面我们用多线程模仿一下火车票售票系统:
public
class TicketSystem
{
public static void main(String[] args)
{
SellThread st=new SellThread();
new Thread(st).start();new Thread(st).start();new Thread(st).start();
}
}
class
SellThread implements Runnable
{
int tickets=100;
public void run()
{
while(true)
{
if(tickets>0)
{
System.out.println("obj:"+Thread.currentThread().getName()+" sell tickets:"+tickets);
tickets--;
}
}
}
}
程序输出了线程0、1、2三个线程从第100张票卖到第1张票的过程,这个程序正确的输出了。但是实际情况中火车票售票系统是常年运行的,有可能第一顾客已经买到了最后一张票,但是执行到tickets--的时候,线程切换了,这时候另外一个顾客也买最后一张票,这时候系统显示还有票,这时候这个顾客也订票了,并且也在执行到tickets--的时候,线程切换。再回去执行原来的线程,前个顾客买到了最后一张票,后一个顾客但是却买到了第0张票。显然这个是不对的。下面我们修改上面程序模拟一下:
class
SellThread implements Runnable
{
int tickets=100;
public void run()
{
while(true)
{
if(tickets>0)
{
Try//让线程睡眠10毫秒,只是修改了这里
{
Thread.sleep(10);
} catch (InterruptedExceptione)
{
e.printStackTrace();
}
System.out.println("obj:"+Thread.currentThread().getName()+" sell tickets:"+tickets);
tickets--;
}
}
}
}
结果的一部分如下:
obj:Thread-0 sell tickets:2
obj:Thread-2 sell tickets:2
obj:Thread-1 sell tickets:0
obj:Thread-0 sell tickets:-1
我们可以看出上面程序两次售出了第二张票,并且卖出了第0张和-1张票,显然这个结果是不对的。遇到了不对的情况,我们就应该得想办法解决它,在Java中运用同步的方法解决这个问题。
在介绍之前我们先说一下临界区,在Java中代码段访问了同一个对象或数据,那么这个代码段就叫做临界区。上面程序中run()方法中循环里面的代码就叫做临界区。我们需要对这个临界区进行保护,这样就用到了线程的同步。
在Java中线程的同步有两种方法,一种是同步块,另一种是同步方法。不管是哪种方法都用到了synchronized关键字。下面我们就修改上面的程序用实例显示一下:
class SellThread implementsRunnable
{
int tickets=100;
Object obj = new Object();
public void run()
{
while(true)
{
synchronized(obj)//加上一个同步关键字
{
if(tickets>0)
{
try{
Thread.sleep(10);
} catch (InterruptedExceptione)
{
e.printStackTrace();
}
System.out.println("obj:"+Thread.currentThread().getName()+" sell tickets:"+tickets);
tickets--;
}
}
}
}
}
上面使用synchronized关键字的时候需要一个对象,这里的对象可以是任意对象,我们在这里选择的是Object对象,你也可以选择String类的对象。每一个对象都有一个监视器或者叫锁。当我将obj作为参数传给synchronized关键字的时候,就相当于给这段代码加了一个锁,当我执行到这段代码的时候,先判断是否加锁,如果没有加锁,先将其加锁然后执行代码。如果加锁了只能等待。等到给代码加锁的线程执行完成之后,会将锁打开。
下面我们介绍同步方法,我们还是以程序的形式给出:
class SellThread implements Runnable
{
int tickets=100;
Object obj = new Object();
public synchronized void sell()//用关键字sychronized //关键字标志同步方法
{
if(tickets>0)
{
try
{
Thread.sleep(10);
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println("sell():"+Thread.currentThread().getName()+
" sell tickets:"+tickets);
tickets--;
}
}
public void run()
{
while(true)
{
sell();
}
}
}
上面的程序用sychronized关键字直接标志的是sell()方法,我们在run()方法里调用sell()的时候,sell()方法中的代码就相当于一个整体都一起执行。但是同步方法也是使用加锁的方法进行同步的,它不像同步块那样传递一个对象,那么他是对哪个对象加的锁呢?同步方法是对程序中的this对象加锁以实现同步的。
我们有时候会写一些静态的方法,这些方法也必须同步。静态方法只属于类本身,没有this对象,那么它对谁加锁呢?前面我们介绍过每一个类都有一个Class类的对象(详细介绍请看:http://blog.csdn.net/mengxiangyue/article/details/6831820),静态方法正是对这个Class类的对象进行加锁以实现同步方法的。
对于同步方法就先介绍到这里,如果有错请大家指出,希望对大家有帮助。
分享到:
相关推荐
多线程同步解决卖票问题
基于Java多线程同步技术的简易模拟售票系统实现.pdf
编写多线程程序是一件烦琐的技术而且还涉及很多不安全的因素。Java 的出现,使得编写安全高效的多线程技术变得简单,但 ...本文介绍了长途汽车售票系统中所涉及的问题来说明Java 多线程技术同步机制的实现。
本文档简单的设计了java多线程机制,其中主要实现了java的线程同步,以火车票售票系统来表现
模拟电影院的多线程购票系统,使用同步锁机制保证数据的安全,同时使用集合的减法来进行,顾客买票时选购位置
java多线程实现火车售票系统以及java中的同步的实现同步块和同步方法同时同步[归纳].pdf
java编写的同步售票存票系统 利用了多线程的同步锁机制 对初学线程的人来说 是个不错的案例
Java多线程同步机制在网络售票系统中的应用.pdf
基于Java多线程同步技术的简易模拟售票系统实现
Java多线程同步机制在网络售票系统中的应用
Java语言是一个支持网络计算的面向对象程序设计语言,吸收了Smalltalk语言和C++语言的优点,并增加了其它特性,如... 本系统采用java作为开发语言,来实现安全的、多线程的、可移植航空定票系统,并且降低开发难度。
为保证不会出现卖出同一个票数,要java多线程同步锁。 设计思路:1.创建一个站台类Station,继承Thread,重写run方法,在run方法里面执行售票操作!售票要使用同步锁:即有一个站台卖这张票时,其他站台要等这张票卖...
主要介绍了Java Thread多线程全面解析的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
Java局域网通信——飞鸽传书源代码,大家都知道VB版、VC版还有Delphi版的飞鸽传书软件,但是Java版的确实不多,因此这个Java文件传输实例不可错过,Java网络编程技能的提升很有帮助。 Java聊天程序,包括服务端和...
Java局域网通信——飞鸽传书源代码,大家都知道VB版、VC版还有Delphi版的飞鸽传书软件,但是Java版的确实不多,因此这个Java文件传输实例不可错过,Java网络编程技能的提升很有帮助。 Java聊天程序,包括服务端和...
6.2 没有实现线程安全的火车票售票系统 6.2.1 火车票的类 6.2.2 售票台的类 6.2.3 实现线程安全的火车票售票系统 6.3 知识点扩展——线程的同步知识 6.3.1 为什么要使用同步机制 6.3.2 Synchronized的同步块 6.3.3 ...
这是一个售票系统源代码,其实现的技术原理是JAVA中的多线程,用到了多线程中的同步块和同步方法。