DesignDojo
System DesignLow-Level DesignFAQ
Back to practice
Concurrency & Atomicity·medium·Updated May 3, 2026·By Aditya Jindal

Movie Ticket Booking

Asked at:BookMyShowFandango
Try this problem

Understanding the Problem

🔗 What is a movie ticket booking system?

A platform that lets users search movies, select showtimes across multiple theaters, pick individual seats, and reserve them atomically while handling concurrent booking conflicts.

You're designing the class layer of a movie booking system — the kind that powers BookMyShow or Fandango. The headline is atomic multi-seat reservations: when two users try to book the same seat concurrently, exactly one succeeds. Your job is to define the entities, lock strategy, and state transitions cleanly so that the interviewer sees you understand concurrency and encapsulation.

Requirements

In scope

  • Multi-theater, multi-screen architecture. Each theater has multiple screens; all screens in a theater have the same seat layout (rows A–Z, seats 0–20 = 546 seats).
  • Movie search by title; showtime selection (movie + screen + date/time).
  • Atomic multi-seat reservation: user picks 1–4 seats, all claim succeeds or all fail. No partial bookings.
  • Concurrent conflict resolution: if two threads pick the same seat, exactly one gets it; the other throws an exception.
  • Cancellation releases seats immediately for other users.
  • Confirmation IDs for audit trails.

Out of scope

  • Payment processing, PCI compliance.
  • Variable seat pricing or types (premium, accessible).
  • Reservation auto-expiry / TTL (PENDING → auto-release after timeout).
  • Notifications, emails, or UI rendering.
  • Rescheduling or seat exchanges.

State your assumptions: you're building the BookingSystem orchestrator and supporting entity classes. Lock scope and synchronization are your main design decision.

The Set Up

Entities & Relationships

  • BookingSystem (orchestrator): searches movies and theaters; initiates reservations. Owns a collection of theaters.
  • Theater: container for multiple screens with identical seat layouts. Queries showtime availability.
  • Screen: owns a 2D array of seats (rows A–Z, cols 0–20). Manages seat state transitions and atomically claims multi-seat reservations. This is the concurrency hot zone.
  • Showtime: links a movie, screen, and temporal slot (date + time). Immutable once created.
  • Seat: individual booking unit with state (AVAILABLE | RESERVED) and a nullable reservation ID. Owned by Screen.
  • Reservation: transaction record with a UUID, status (PENDING | CONFIRMED | CANCELLED), list of booked seats, and showtime reference. Returned to caller on success.

Dependency sketch: BookingSystem → Theater → Showtime → Screen → Seats. Reservation is generated by BookingSystem and returned to the caller. Screen owns the seat-locking invariants.

Class Design

enum SeatState { AVAILABLE, RESERVED }
enum ReservationStatus { PENDING, CONFIRMED, CANCELLED }

class Seat:
  row: char                    // A-Z
  number: int                  // 0-20
  state: SeatState
  reservedBy: String?          // Reservation ID (null if AVAILABLE)

class Showtime:
  id: String
  movie: Movie
  screen: Screen
  dateTime: DateTime
  getAvailableSeats() -> List<Seat>  // read-only view of available seats

class Screen(rows=26, cols=21):
  seats: Seat[rows][cols]
  
  synchronized reserveSeats(seatList: List<Seat>, reservationId: String) -> void:
    // Atomically claim all seats or fail with exception
    // Throws ReservationConflictException if any seat is unavailable
  
  synchronized releaseSeats(reservationId: String) -> void:
    // Clear the reservedBy flag; mark seats AVAILABLE

class Reservation:
  id: String                   // UUID
  showtime: Showtime
  seats: List<Seat>
  status: ReservationStatus    // PENDING, CONFIRMED, CANCELLED
  createdAt: DateTime
  
  getConfirmationId() -> String

class Theater:
  id: String
  name: String
  screens: Map<String, Screen>
  
  searchShowtimes(movieTitle: String, date: Date) -> List<Showtime>

class BookingSystem:
  theaters: Map<String, Theater>
  
  searchMovies(title: String) -> List<Movie>
  searchShowtimes(movie: Movie, date: Date) -> List<Showtime>
  
  reserveSeats(showtime: Showtime, seatList: List<Seat>) -> Reservation:
    // Throws ReservationConflictException if conflict detected
  
  cancelReservation(reservationId: String) -> void:
    // Throws ReservationNotFoundException if not found

Implementation

The meaty method is Screen.reserveSeats — this is where you guarantee atomicity under concurrent load.

Screen.reserveSeats(seatList: List<Seat>, reservationId: String) -> void:
  synchronized(this):  // Lock the entire Screen object
    // Phase 1: Validate all seats are AVAILABLE
    for seat in seatList:
      if seat.state != AVAILABLE:
        throw ReservationConflictException(
          "Seat " + seat.row + seat.number + " already reserved"
        )
    
    // Phase 2: Claim all seats atomically (no context switch possible)
    for seat in seatList:
      seat.state = RESERVED
      seat.reservedBy = reservationId

Screen.releaseSeats(reservationId: String) -> void:
  synchronized(this):
    for each seat in seats array:
      if seat.reservedBy == reservationId:
        seat.state = AVAILABLE
        seat.reservedBy = null

BookingSystem.reserveSeats(showtime: Showtime, seatList: List<Seat>) -> Reservation:
  // Validate all seats belong to the showtime's screen (fail fast)
  for seat in seatList:
    if seat not in showtime.screen.seats:
      throw InvalidSeatException("Seat not in this showtime's screen")
  
  reservation = new Reservation(
    id: UUID.randomUUID(),
    showtime: showtime,
    seats: seatList,
    status: PENDING,
    createdAt: now()
  )
  
  // This call may throw ReservationConflictException
  showtime.screen.reserveSeats(seatList, reservation.id)
  
  return reservation

Trace through a concurrent scenario:

Showtime: Movie X, 2pm, Screen 1.
Seats to book: [A1, A2] (Thread 1) and [A1, A3] (Thread 2).

Time    Thread 1                          Thread 2
----    ---------                         ---------
T0      reserveSeats([A1, A2])           reserveSeats([A1, A3])
T1      acquire lock on Screen 1         waiting for lock
T2      Phase 1: check A1.state          (blocked)
T3      A1 == AVAILABLE ✓
T4      check A2.state
T5      A2 == AVAILABLE ✓
T6      Phase 2: claim A1 → RESERVED
T7      claim A2 → RESERVED
T8      release lock                     acquire lock
T9      return Reservation(id=U1,        Phase 1: check A1.state
        status=PENDING)                  
T10                                      A1 == RESERVED ✗
T11                                      throw ReservationConflictException("A1 already reserved")
T12                                      release lock

Result: Thread 1 succeeds with seats [A1, A2]. Thread 2 fails immediately on A1 (before claiming A3). No partial bookings. The lock ensured both validation and claiming happened atomically.

Extensibility

Likely follow-ups in the interview:

  • Reservation auto-expiry (TTL): Add expiresAt: DateTime to Reservation and a background ReservationExpirer thread that polls PENDING reservations. When createdAt + TTL < now, call cancelReservation(id) to release seats. Seat state transitions: AVAILABLE → RESERVED (pending) → AVAILABLE (expired) or CONFIRMED (user paid).

  • Seat pricing by type: Add type: enum SeatType { STANDARD, PREMIUM, ACCESSIBLE } to Seat. Reservation tracks pricePerSeat: Map<Seat, BigDecimal>. During reserveSeats, calculate total from seat type → price mapping. Return Reservation with totalPrice so caller can review before confirm.

  • Group discounts: Add discountCode: String? to Reservation. During confirm, if code is set, BookingSystem applies a multiplier to totalPrice. No changes to seat-locking logic.

  • Multi-screen reservation (rare): If a user tries to book seats across two different screens, decompose into two separate Screen.reserveSeats calls. If the second fails, rollback the first via releaseSeats. This is a distributed transaction — simple two-phase commit.

What is Expected at Each Level?

Mid-level

  • Identifies the core entities: BookingSystem, Theater, Screen, Seat, Showtime, Reservation.
  • Recognizes that Screen is the concurrency hot zone and implements synchronized methods.
  • Writes the happy path for multi-seat reservation without race conditions (validation + claiming in one lock).
  • Handles the basic case: two threads, same seat, one wins.

Senior

  • Designs the Reservation return type as an enum-backed status (PENDING, CONFIRMED, CANCELLED), not a bare boolean.
  • Explains why synchronizing on Screen (coarse-grained lock) is simpler and safer than per-Seat locks.
  • Traces through the concurrent scenario clearly, showing how the lock prevents partial bookings.
  • Mentions the cost: high contention during peak hours (movie release day, blockbuster showtime).
  • Anticipates one extensibility follow-up cleanly (e.g., TTL or pricing).

Staff+

  • Pushes back on vague requirements: "What happens if a user reserves seats from two different screens in one transaction? Do you fail atomically, or accept partial?"
  • Names the pattern: "This is a critical section problem. I'm using a monitor (synchronized block) to ensure mutual exclusion."
  • Speaks to testability: "I'd unit-test the happy path, the conflict case, and the rollback-on-cancel. I'd integration-test with a thread pool simulating 100 concurrent users."
  • Discusses failure modes: What if the JVM crashes after we claim seats but before we return the Reservation? (Suggests durable logging: write to a reservation log before returning.)
  • Considers observability: How do you monitor lock contention? Warn ops when reserveSeats latency spikes during peak hours?

Ready to design it?

Walk through Movie Ticket Booking stage-by-stage with AI feedback.

Start practice

On this page

  • Understanding the Problem
  • Requirements
  • The Set Up
  • Entities &#x26; Relationships
  • Class Design
  • Implementation
  • Extensibility
  • What is Expected at Each Level?
  • Mid-level
  • Senior
  • Staff+
DesignDojo

Free, open-source system design + LLD interview practice. Bring your own AI key.

Practice
  • System Design
  • Low-Level Design
Write-ups
  • High Level Design
  • Low-Level Design
Resources
  • FAQ
  • vs HelloInterview
  • GitHub
  • Sitemap
Project
  • About
  • License · MIT
  • Privacy
  • Contact
© 2026 DesignDojo · Free & open source
For AI agents

Ask AI about Movie Ticket Booking