Concurrency Patterns: Balking Pattern – DEV Community
December 24, 2024

Concurrency Patterns: Balking Pattern – DEV Community



introduce

this Hesitation design pattern Is a behavioral design pattern for managing state-related operations in a system. It ensures that operations are performed only when the system is in an appropriate state. If the required prerequisites are not met, the operation aborts or the system “hesitates.” For those like me who don’t know what Balking is, here’s what Google has to say about it: “Hesitation or unwillingness to accept an idea or commitment”. This mode is particularly useful in multi-threaded environments or systems where invalid operations may cause conflicts or errors.

Some in the community also believe that the hesitation pattern is more of an anti-pattern than a design pattern. If an object cannot support its API, it should restrict the API so that the call in question is unavailable, or so that the call can be made without restriction. This is an old pattern that seems to have emerged when the JVM was slower and synchronization was not as well understood and implemented as it is today. Regardless, it’s worth discussing and it’s up to the developer whether to use it or not.



The hesitation model relies on three basic concepts

  1. Guard status: Conditions that must be met to continue the operation.
  2. Dependence on state action: Operations that depend on the current state of the system.
  3. Thread safety: This pattern often uses locks or other synchronization mechanisms to ensure safety in concurrent environments.

Let us understand this through an example:

The printing system demonstrates hesitation mode:

  • Imagine: A printer can only handle one print request at a time. Even multiple processes can issue print requests.
  • Guard status: Print must not actively “Print” to process new print requests.
  • Behavior: If the printer is busy, the system will stop processing new print requests.

notes: Yes, we could use queues to handle this, but for now let’s assume we don’t know that such an elegant data structure exists.

import threading
import time

class Printer:
    def __init__(self):
        self.state = "idle"
        self.lock = threading.Lock()

    def start_printing(self, job_id):
        print(f"Attempting to start Print Job {job_id}...")

        with self.lock:  # Ensure thread safety
            if self.state == "printing":
                print(f"Balking: Print Job {job_id} cannot start. Printer is busy.")
                return
            self.state = "printing"

        # Simulate the printing process
        print(f"Print Job {job_id} started.")
        time.sleep(3)
        print(f"Print Job {job_id} completed.")

        with self.lock:
            self.printing = "idle"

# Multiple threads attempting to start print jobs
printer = Printer()

threads = [
    threading.Thread(target=printer.start_printing, args=(1,)),
    threading.Thread(target=printer.start_printing, args=(2,))
]

for t in threads:
    t.start()

for t in threads:
    t.join()
Enter full screen mode

Exit full screen mode

Looking at the code we can see that if we send a print request start_printing arrive printer and printer Busy it checks its current status self.state If the status is “printing” it will return without doing anything. Otherwise, it will accept the request and adjust its status accordingly.



When to use hesitation mode

  1. multi-threaded system: Prevent race conditions or invalid operations.
  2. Status related workflow: When the operation is only allowed in certain states.
  3. Resource management: Prevent improper use of shared resources. Objects using this mode are usually in a state of temporary indecision for an unknown duration. If the object is to remain in a hesitation-prone state for a known, limited time, protective suspension mode may be preferred.



Advantages of hesitation mode

  1. Prevent invalid operations: Guard ensures that operations only occur under valid conditions.
  2. Thread safety: Particularly useful in multi-threaded systems.
  3. Simplify the logic: Encapsulate state-related operations into clear, reusable patterns.



shortcoming

  1. Limited applicability: Most useful when the action is binary (allow or disallow).
  2. potential overhead: Protection checks and synchronization mechanisms come with performance costs.



in conclusion

The Balking design pattern provides an efficient way to manage state-related operations and prevent invalid operations in software systems. The reliability and maintainability of the system are enhanced by introducing explicit protection conditions and ensuring thread safety. Whether preventing multiple trips in a taxi reservation system or managing concurrent print jobs, the Balking pattern provides a structured approach to avoiding conflicts and maintaining operational integrity. Ultimately, the choice to use hesitant mode depends on the specific requirements of your application and its concurrency needs.



refer to

2024-12-24 18:52:52

Leave a Reply

Your email address will not be published. Required fields are marked *