diff --git a/coarse-grained-lock/README.md b/coarse-grained-lock/README.md
new file mode 100644
index 000000000000..fde006aaa0f1
--- /dev/null
+++ b/coarse-grained-lock/README.md
@@ -0,0 +1,105 @@
+---
+Title: "Coarse-Grained Lock Pattern in Java: Simplifying Thread-Safe Operations"
+Short Title: Coarse-Grained Lock
+Description: "Coarse-Grained Lock pattern ensures thread safety by holding a global lock for related objects instead of multiple locks."
+Category: Concurrency
+Tags:
+
+ Concurrency
+ Synchronization
+ Thread Safety
+ Locking Mechanisms
+---
+
+
+## Intent of Coarse-Grained Lock Design Pattern
+
+The Coarse-Grained Lock pattern simplifies synchronization in multithreaded systems by applying a single lock to a group of operations or a shared resource. This design reduces the complexity of managing multiple fine-grained locks, albeit at the cost of some parallelism.
+## Detailed Explanation of Coarse-Grained Lock Pattern with Real-World Examples
+
+Real-world example
+
+> Imagine a bank system where multiple threads handle customer transactions such as deposits, withdrawals, and balance checks. To ensure account integrity, a coarse-grained lock can be applied to the entire account object. While this reduces concurrency, it simplifies synchronization logic and prevents data inconsistencies.
+
+In plain words
+
+> A Coarse-Grained Lock is a single lock used to control access to a shared resource or related group of operations. It’s a simple way to ensure thread safety when fine-grained locking would be too complex to manage.
+
+
+## Programmatic Example of Coarse-Grained Locks Pattern in Java
+
+The Coarse-Grained Lock pattern is used to synchronize access to multiple related objects. In this example, we demonstrate how to use a single lock to coordinate updates to a customer and their associated addresses.
+
+**Locking the Address and Customer Objects**
+
+```java
+package com.iluwatar.coarse.grained;
+
+/**
+ * Demonstrates the Coarse-Grained Lock pattern.
+ */
+public class App {
+
+ /**
+ * Program entry point.
+ *
+ * @param args command line arguments
+ */
+ public static void main(String[] args) {
+ // Create a lock instance to synchronize access
+ Lock lock = new Lock();
+
+ // Create a customer and their addresses
+ Customer customer = new Customer(55, "John");
+ Address address1 = new Address(customer.getCustomerId(), 1, "Chicago");
+ Address address2 = new Address(customer.getCustomerId(), 2, "Houston");
+
+ // Use the lock to synchronize modifications to customer and addresses
+ lock.synchronizedMethod(() -> {
+ customer.setName("Smith");
+ address1.setCity("Dallas");
+ address2.setCity("Phoenix");
+ });
+ }
+}
+
+```
+Both Addresses and customer objects can only be changed by a single thread, otherwise if another thread attempts to access a variable, then no update will occur. This example demonstrates how the Coarse-Grained Lock ensures thread-safe modifications across related objects, simplifying concurrency management while maintaining accuracy.
+
+## When to Use the Coarse-Grained Lock Pattern in Java
+
+The Coarse-Grained Lock pattern is applicable:
+
+* When ensuring thread safety in a multithreaded environment with shared resources.
+* For applications where ease of implementation outweighs the need for high concurrency.
+* When fine-grained locking introduces complexity or increases the risk of deadlocks.
+
+## Real-World Applications of Coarse-Grained Pattern in Java
+
+* Ensuring the integrity of account transactions in Banking Systems.
+* Preventing concurrent threads from corrupting shared log files in Inventory Management Systems.
+* Synchronizing stock operations to prevent over-selling.
+
+## Benefits and Trade-Offs of Coarse-Grained Lock Pattern
+Benefits:
+
+* Easier to implement and debug compared to fine-grained locking.
+* Reduces the chances of deadlocks due to fewer locks being used.
+* Ensures data consistency in critical sections.
+
+Trade-Offs:
+
+* Limits the ability of threads to perform parallel operations on shared resources.
+* Can lead to contention when multiple threads compete for the same lock.
+* Operations that don’t require synchronization are still blocked.
+
+## Related Patterns
+
+- Readers–writer lock: allows for concurrent access for read-only operations, while requiring an exclusive lock for write operations.
+- Lock Manager pattern: Can be used to define graunality in coarse-grained locks, as well as, detection and handling of deadlocks.
+- Fine-Grained Lock: Increases concurrency by locking smaller portions of code or objects.
+## References and Credits
+
+* [Java Concurrency in Practice](https://amzn.to/4cYY4kU)
+* [Patterns of Enterprise Application Architecture](https://amzn.to/3Uh7rW1)
+* [Oracle java concurrency](https://docs.oracle.com/javase/tutorial/essential/concurrency/)
diff --git a/coarse-grained-lock/coarse-grained-lock.iml b/coarse-grained-lock/coarse-grained-lock.iml
new file mode 100644
index 000000000000..9e3449c9d8f0
--- /dev/null
+++ b/coarse-grained-lock/coarse-grained-lock.iml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/coarse-grained-lock/etc/coarse-grained-lock.urm.png b/coarse-grained-lock/etc/coarse-grained-lock.urm.png
new file mode 100644
index 000000000000..3faee2e9cdb9
Binary files /dev/null and b/coarse-grained-lock/etc/coarse-grained-lock.urm.png differ
diff --git a/coarse-grained-lock/etc/coarse-grained-lock.urm.puml b/coarse-grained-lock/etc/coarse-grained-lock.urm.puml
new file mode 100644
index 000000000000..d79f4427590e
--- /dev/null
+++ b/coarse-grained-lock/etc/coarse-grained-lock.urm.puml
@@ -0,0 +1,42 @@
+@startuml
+package com.iluwatar.coarse.grained {
+
+ class App {
+ + App()
+ + main(args: String[]) {static}
+ }
+
+ class Lock {
+ + synchronizedMethod(task: Runnable): void
+ }
+
+ class Customer {
+ - customerId: int
+ - name: String
+ + Customer(customerId: int, name: String)
+ + setCustomerId(customerId: int): void
+ + getCustomerId(): int
+ + getName(): String
+ + setName(name: String): void
+
+ }
+
+ class Address {
+ - addressId: int
+ - customerId: int
+ - city: String
+ + Address(customerId: int, addressId: int, city: String)
+ + getAddressId(): int
+ + getCustomerId(): int
+ + getCity(): String
+ + setAddressId(addressId: int): void
+ + setCustomerId(customerId: int): void
+ + setCity(city: String): void
+ }
+
+ Lock --> Customer : "Protects"
+ Lock --> Address : "Protects"
+
+}
+
+@enduml
diff --git a/coarse-grained-lock/pom.xml b/coarse-grained-lock/pom.xml
new file mode 100644
index 000000000000..6647dc56e663
--- /dev/null
+++ b/coarse-grained-lock/pom.xml
@@ -0,0 +1,33 @@
+
+
+ 4.0.0
+
+ com.iluwatar
+ java-design-patterns
+ 1.26.0-SNAPSHOT
+
+
+ coarse-grained-lock
+
+
+ 17
+ 17
+ UTF-8
+
+
+
+ org.testng
+ testng
+ 7.10.2
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+
+
\ No newline at end of file
diff --git a/coarse-grained-lock/src/main/java/com/iluwatar/coarse/grained/Address.java b/coarse-grained-lock/src/main/java/com/iluwatar/coarse/grained/Address.java
new file mode 100644
index 000000000000..7ae20c269009
--- /dev/null
+++ b/coarse-grained-lock/src/main/java/com/iluwatar/coarse/grained/Address.java
@@ -0,0 +1,85 @@
+package com.iluwatar.coarse.grained;
+
+/**
+ * Represents an address with attributes customerId, addressId, and city.
+ * This class associates a customer's address with a unique ID and provides
+ * getter and setter methods to manage its attributes.
+ */
+public class Address {
+
+ /** Unique identifier for the address. */
+ private int addressId;
+
+ /** Identifier of the customer associated with the address. */
+ private int customerId;
+
+ /** The city where the address is located. */
+ private String city;
+
+ /**
+ * Constructs an {@code Address} object with the specified customer ID, address ID, and city.
+ *
+ * @param customerId the ID of the customer
+ * @param addressId the unique ID of the address
+ * @param city the city of the address
+ */
+ public Address(int customerId, int addressId, String city) {
+ this.customerId = customerId;
+ this.addressId = addressId;
+ this.city = city;
+ }
+
+ /**
+ * Returns the unique address ID.
+ *
+ * @return the address ID
+ */
+ public int getAddressId() {
+ return addressId;
+ }
+
+ /**
+ * Updates the address ID with the specified value.
+ *
+ * @param addressId the new address ID
+ */
+ public void setAddressId(int addressId) {
+ this.addressId = addressId;
+ }
+
+ /**
+ * Returns the ID of the customer associated with the address.
+ *
+ * @return the customer ID
+ */
+ public int getCustomerId() {
+ return customerId;
+ }
+
+ /**
+ * Updates the customer ID with the specified value.
+ *
+ * @param customerId the new customer ID
+ */
+ public void setCustomerId(int customerId) {
+ this.customerId = customerId;
+ }
+
+ /**
+ * Returns the city where the address is located.
+ *
+ * @return the city name
+ */
+ public String getCity() {
+ return city;
+ }
+
+ /**
+ * Updates the city name with the specified value.
+ *
+ * @param city the new city name
+ */
+ public void setCity(String city) {
+ this.city = city;
+ }
+}
diff --git a/coarse-grained-lock/src/main/java/com/iluwatar/coarse/grained/App.java b/coarse-grained-lock/src/main/java/com/iluwatar/coarse/grained/App.java
new file mode 100644
index 000000000000..7c84e75dc088
--- /dev/null
+++ b/coarse-grained-lock/src/main/java/com/iluwatar/coarse/grained/App.java
@@ -0,0 +1,30 @@
+package com.iluwatar.coarse.grained;
+/**
+ * The coarse grained lock is a pattern designed to handle locking multiple objects at the same time;
+ * for instance, a customer can have multiple addresses and wants to change an information regarding them.
+ * It makes more buissenes logic to lock both the customer and the addresses in order to avoid any confuison.
+ * This reduces concurrent programming but ensures a more simple code that can work accurately.
+ */
+
+public class App {
+
+ /**
+ * Program entry point.
+ *
+ * @param args command line args
+ */
+
+ public static void main(String[] args) {
+ Lock lock = new Lock();
+ Customer customer = new Customer(55, "john");
+ Address address1 = new Address(customer.getCustomerId(), 1, "chicago");
+ Address address2 = new Address(customer.getCustomerId(), 2, "houston");
+
+ lock.synchronizedMethod(() -> {
+ customer.setName("smith");
+ address1.setCity("dallas");
+ address2.setCity("phoenix");
+ });
+ }
+
+}
\ No newline at end of file
diff --git a/coarse-grained-lock/src/main/java/com/iluwatar/coarse/grained/Customer.java b/coarse-grained-lock/src/main/java/com/iluwatar/coarse/grained/Customer.java
new file mode 100644
index 000000000000..1d465bbeb2cd
--- /dev/null
+++ b/coarse-grained-lock/src/main/java/com/iluwatar/coarse/grained/Customer.java
@@ -0,0 +1,61 @@
+package com.iluwatar.coarse.grained;
+
+/**
+ * Represents a customer with a unique ID and a name.
+ * Provides methods to access and modify customer attributes.
+ */
+public class Customer {
+
+ /** The name of the customer. */
+ private String name;
+
+ /** The unique identifier for the customer. */
+ private int customerId;
+
+ /**
+ * Constructs a {@code Customer} object with the specified ID and name.
+ *
+ * @param customerId the unique ID of the customer
+ * @param name the name of the customer
+ */
+ public Customer(int customerId, String name) {
+ this.customerId = customerId;
+ this.name = name;
+ }
+
+ /**
+ * Returns the name of the customer.
+ *
+ * @return the customer's name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Updates the name of the customer.
+ *
+ * @param name the new name of the customer
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Returns the unique ID of the customer.
+ *
+ * @return the customer ID
+ */
+ public int getCustomerId() {
+ return customerId;
+ }
+
+ /**
+ * Updates the unique ID of the customer.
+ *
+ * @param customerId the new customer ID
+ */
+ public void setCustomerId(int customerId) {
+ this.customerId = customerId;
+ }
+}
diff --git a/coarse-grained-lock/src/main/java/com/iluwatar/coarse/grained/Lock.java b/coarse-grained-lock/src/main/java/com/iluwatar/coarse/grained/Lock.java
new file mode 100644
index 000000000000..217b88327ff2
--- /dev/null
+++ b/coarse-grained-lock/src/main/java/com/iluwatar/coarse/grained/Lock.java
@@ -0,0 +1,23 @@
+package com.iluwatar.coarse.grained;
+
+/**
+ * Implements a coarse-grained lock for synchronizing tasks.
+ * This class provides a mechanism to ensure thread safety by wrapping tasks
+ * inside a synchronized block.
+ */
+public class Lock {
+
+ /** The internal lock object used for synchronization. */
+ private final Object newLock = new Object();
+
+ /**
+ * Executes a given task within a synchronized block, ensuring thread safety.
+ *
+ * @param task the {@code Runnable} task to be executed in a synchronized context
+ */
+ public void synchronizedMethod(Runnable task) {
+ synchronized (newLock) {
+ task.run();
+ }
+ }
+}
diff --git a/coarse-grained-lock/src/test/java/com/iluwatar/coarse/grained/AppTest.java b/coarse-grained-lock/src/test/java/com/iluwatar/coarse/grained/AppTest.java
new file mode 100644
index 000000000000..3af2e828ea45
--- /dev/null
+++ b/coarse-grained-lock/src/test/java/com/iluwatar/coarse/grained/AppTest.java
@@ -0,0 +1,73 @@
+package com.iluwatar.coarse.grained;
+
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Unit tests for the {@link App} class.
+ */
+class AppTest {
+
+ @Test
+ void testLockingMechanism() {
+ // Arrange
+ Lock lock = new Lock();
+ Customer customer = new Customer(55, "john");
+ Address address1 = new Address(customer.getCustomerId(), 1, "chicago");
+ Address address2 = new Address(customer.getCustomerId(), 2, "houston");
+
+ // Act
+ lock.synchronizedMethod(() -> {
+ customer.setName("smith");
+ address1.setCity("dallas");
+ address2.setCity("phoenix");
+ });
+
+ // Assert
+ assertEquals("smith", customer.getName(), "Customer name should be updated to 'smith'.");
+ assertEquals("dallas", address1.getCity(), "Address 1 city should be updated to 'dallas'.");
+ assertEquals("phoenix", address2.getCity(), "Address 2 city should be updated to 'phoenix'.");
+ }
+
+ @Test
+ void testConcurrentModification() throws InterruptedException {
+ // Arrange
+ Lock lock = new Lock();
+ Customer customer = new Customer(55, "john");
+ Address address1 = new Address(customer.getCustomerId(), 1, "chicago");
+ Address address2 = new Address(customer.getCustomerId(), 2, "houston");
+
+ // Simulate two threads attempting to modify data
+ Thread thread1 = new Thread(() -> lock.synchronizedMethod(() -> {
+ customer.setName("alice");
+ address1.setCity("seattle");
+ }));
+
+ Thread thread2 = new Thread(() -> lock.synchronizedMethod(() -> {
+ customer.setName("bob");
+ address2.setCity("miami");
+ }));
+
+ // Act
+ thread1.start();
+ thread2.start();
+ thread1.join();
+ thread2.join();
+
+ /*
+ Assert
+ Only one thread's changes should be applied because of locking.
+ The output can be either customer names depending on the thread that will finish last.
+ both addresses will update as each thread access only one resource and not both at the same time.
+ */
+ assertTrue(
+ customer.getName().equals("alice") || customer.getName().equals("bob"),
+ "Customer name should reflect changes from one thread only."
+ );
+ assertEquals("seattle", address1.getCity(),
+ "Address cities should reflect changes from one thread only.");
+
+ assertEquals("miami", address2.getCity(),
+ "Address cities should reflect changes from one thread only.");
+ }
+}