多线程共享同一资源时,在某一时间点上会出现多个线程同时访问资源的情况。虽然编译没有问题,但是实际用起来却很有可能造成困扰。比如车站卖票,把同一个号的两张票卖给两个人,特别是卖火车票的时候,恐怕这两位拿同一号的乘客就会闹矛盾了。比如下面的这个小例子:
代码:
class MyThread4 implements Runnable{
private int ticket = 8;//定义8张票
public void run(){
for(int i=0;i<100;i++){
if(this.ticket>0){
try{
Thread.sleep(100);
}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"号窗口"+
"==>On sael#######"+(ticket--));
}
}
}
}
public class Tongbukuai {
public static void main(String [] args){
MyThread4 mt = new MyThread4();//共享同一资源
Thread t1 = new Thread(mt);//
Thread t2 = new Thread(mt);//三个线程代表三个售票窗口
Thread t3 = new Thread(mt);//
t1.start();
t2.start();
t3.start();
}
}
运行结果:
这怎么可以?2号和1号窗口卖出了两张8号票,而且卖出的票的总数是不正常的。这是因为多个线程同时进入取票的循环,而程序还没来得及把票数减一;后面的0号和-1号票的出现是因为当ticket 数为1的时候0号、1号和2号三个线程进入循环里,0号取得了1号票,此时应该停止买票了,但是1号、2号线程还在循环里,所以就依次取出了0号和-1号票。
这种情况的处理办法就是为资源加上一把“锁”。每次只允许一个线程进入,当前的线程结束操作后才允许下一个线程进入。实现加同步锁的操作有两种方法:1、同步块 2、同步方法。两种方法都要用到synchronized关键字。
代码及运行结果如下:
同步块:
class MyThread4 implements Runnable{
private int ticket = 8;//定义8张票
public void run(){
for(int i=0;i<8;i++){
synchronized(this){
if(this.ticket>0){
try{
Thread.sleep(100);
}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"号窗口"+
"==>On sael#######"+(ticket--));
}
}
}
}
}
public class Tongbukuai {
public static void main(String [] args){
MyThread4 mt = new MyThread4();//共享同一资源
Thread t1 = new Thread(mt);//
Thread t2 = new Thread(mt);//三个线程代表三个售票窗口
Thread t3 = new Thread(mt);//
t1.start();
t2.start();
t3.start();
}
}
运行结果:
同步方法:
class MyThread4 implements Runnable{
private int ticket = 8;//定义8张票
public void run(){
for(int i=0;i<8;i++){
try{
Thread.sleep(100);
}catch(Exception e){}
this.sale();
}
}
public synchronized void sale(){
{
if(ticket>0)
{
System.out.println(Thread.currentThread().getName()+"号窗口"+this.ticket--+"号票");
}
}
}
}
public class Tongbukuai {
public static void main(String [] args){
MyThread4 mt = new MyThread4();//共享同一资源
Thread t1 = new Thread(mt);//
Thread t2 = new Thread(mt);//三个线程代表三个售票窗口
Thread t3 = new Thread(mt);//
t1.start();
t2.start();
t3.start();
}
}
运行结果:
注意synchronized的位置,不要放错位置哦!
我的这个就放错了= =!!
class MyThread4 implements Runnable{
private int ticket = 8;//定义8张票
public void run(){
synchronized(this){ //一个窗口全部卖完
for(int i=0;i<8;i++){
if(this.ticket>0){
try{
Thread.sleep(100);
}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"号窗口"+"==>On sael#######"+(ticket--));
}
}
}
}
}
public class Tongbukuai {
public static void main(String [] args){
MyThread4 mt = new MyThread4();//共享同一资源
Thread t1 = new Thread(mt);//
Thread t2 = new Thread(mt);//三个线程代表三个售票窗口
Thread t3 = new Thread(mt);//
t1.start();
t2.start();
t3.start();
}
}
看看结果:
虽然没卖重号的票,也没多卖出0、-1号的,但是却全都是一个窗口--0号窗口卖出去的。因为在ti也就是0号线程start的时候调用run()方法,然后0号就悲剧的被错位的synchronized锁在了里面,所以只能一个窗口全部卖完了。
提醒一下大家,不要犯类似的错误。