多线程synchronized实现简单的影院购票功能

多线程synchronized实现简单的影院购票功能

由于同一进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了访问冲突的问题。解决该问题的机制是synchronized关键字,它包括两种用法:synchronized 方法和 synchronized 块。

synchronized 方法

通过在方法声明中加入 synchronized关键字来声明,语法如下:

public synchronized void accessVal(int newVal);

synchronized 方法控制对“对象的类成员变量”的访问:每个对象对应一把锁,每个 synchronized 方法都必须获得调用该方法的对象的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。

synchronized 块

synchronized 方法的缺陷:若将一个大的方法声明为synchronized 将会大大影响效率。

Java 为我们提供了更好的解决办法,那就是 synchronized 块。 块可以让我们精确地控制到具体的“成员变量”,缩小同步的范围,提高效率。

synchronized 块:通过 synchronized关键字来声明synchronized 块,语法如下:

synchronized(syncObject)
   { 
   //允许访问控制的代码 
   }

实现简单的影院购票功能

代码如下:

package com.msl.syn;

import java.util.ArrayList;
import java.util.List;

/**
 * 实现简单的影院购票功能 - 快乐影院
 * @author Senley
 *
 */
public class HappyCinema2 {
    public static void main(String[] args) {
        //可用位置
        List<Integer> available = new ArrayList<Integer>();
        available.add(1);
        available.add(2);
        available.add(5);
        available.add(6);
        available.add(7);
        //顾客需要的位置
        List<Integer> seats1 = new ArrayList<Integer>();
        seats1.add(1);
        seats1.add(2);
        List<Integer> seats2 = new ArrayList<Integer>();
        seats2.add(3);
        seats2.add(6);
        
        MslCinema m = new MslCinema(available, "Happy Cinema");
        new Thread(new HappyCustomer(m, seats1),"张三").start();
        new Thread(new HappyCustomer(m, seats2),"李四").start();
    }
    
}

//影院
class MslCinema{
    List<Integer> available; //可用的位置
    String name; //名称
    
    public MslCinema(List<Integer> available, String name) {
        this.available = available;
        this.name = name;
    }
    
    //购票
    public boolean bookTickets(List<Integer> seats) {
        System.out.println("欢迎光临"+this.name+",可用位置为:"+available);
        List<Integer> copy = new ArrayList<Integer>();
        copy.addAll(available);
        //相减
        copy.removeAll(seats);
        //判断大小
        if(available.size()-seats.size()!=copy.size()) {
            return false;
        }
        //成功
        available = copy;
        return true;
    }
}

//顾客
class HappyCustomer implements Runnable{
    MslCinema cinema;
    List<Integer> seats;

    public HappyCustomer(MslCinema cinema, List<Integer> seats) {
        super();
        this.cinema = cinema;
        this.seats = seats;
    }

    @Override
    public void run() {
        synchronized(cinema) {
            boolean flag = cinema.bookTickets(seats);
            if(flag) {
                System.out.println("出票成功--"+Thread.currentThread().getName()+"--位置为"+seats);
            }else {
                System.out.println("出票失败--"+Thread.currentThread().getName()+"--位置不够");        
            }
        }
    }
}

结果如下:

欢迎光临Happy Cinema,可用位置为:[1, 2, 5, 6, 7]
出票成功--张三--位置为[1, 2]
欢迎光临Happy Cinema,可用位置为:[5, 6, 7]
出票失败--李四--位置不够

“synchronized (cinema)” 意味着线程需要获得cinema对象的“锁”才有资格运行同步块中的代码。cinema对象的“锁”也称为“互斥锁”,在同一时刻只能被一个线程使用。A线程拥有锁,则可以调用“同步块”中的代码;B线程没有锁,则进入cinema对象的“锁池队列”等待,直到A线程使用完毕释放了cinema对象的锁,B线程得到锁才可以开始调用“同步块”中的代码。

Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2021-2022 Senley
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信