text: package br.com.leonardoz.features.locks;
  
  import java.util.concurrent.Executors;
  
  /**
   * Every Java object has an intrinsic lock (or a monitor lock) associated with
   * it.
   * 
   * Every Java object can be used as a lock.
   * 
   * Intrinsic Locks are mutually exclusive, so one only thread can 'hold' the
   * lock at time when it's using the synchronization mechanism.
   * 
   * The lock is freed when the synchronized method/block ends.
   * 
   * Synchronize serializes access for what is locked and guarantee memory
   * visibility for the changes that happened inside the synchronized scope to all
   * threads.
   * 
   * Intrinsic locks are reentrant: if you are holding it, you can acquire it
   * again, without deadlocking.
   */
  public class UsingIntrinsicLocks {
  
  	private boolean state;
  
  	/**
  	 * When used in method signature, synchronized use 'this' as a lock.
  	 * 
  	 * Instead of 'this', other objects variables can be used
  	 */
  	public synchronized void mySynchronizedMethod() {
  		state = !state;
  		// Everything in this method can only be accessed by the thread who hold the
  		// lock.
  		System.out.println("My state is:" + state);
  		// Without sync: states have no order guarantee true, true, false, true...
  		// With sync: always true, false, true, false...
  	}
  
  	/**
  	 * It's possible to lock only a block inside the method
  	 */
  	public void mySynchronizedBlock() {
  		/*
  		 * Everything in this block can only be accessed by the thread who hold the
  		 * lock. The message bellow will be printed before the message inside the
  		 * synchronized block
  		 */
  		System.out.println("Who owns my lock: " + Thread.currentThread().getName());
  		synchronized (this) {
  			state = !state;
  			System.out.println("Who owns my lock after state changes: " + Thread.currentThread().getName());
  			System.out.println("State is: " + state);
  			System.out.println("====");
  		}
  	}
  
  	/**
  	 * Already holds a lock when called
  	 */
  	public synchronized void reentrancy() {
  		System.out.println("Before acquiring again");
  		// Tries to hold it without releasing the lock
  		synchronized (this) {
  			System.out.println("I'm own it! " + Thread.currentThread().getName());
  		}
  	}
  
  	public static void main(String[] args) throws InterruptedException {
  		var executor = Executors.newCachedThreadPool();
  		var self = new UsingIntrinsicLocks();
  		for (int i = 0; i < 100; i++) {
  			executor.execute(() -> self.mySynchronizedMethod());
  		}
  		Thread.sleep(1000);
  		for (int i = 0; i < 10; i++) {
  			executor.execute(() -> self.mySynchronizedBlock());
  		}
  		Thread.sleep(1000);
  		for (int i = 0; i < 10; i++) {
  			executor.execute(() -> self.reentrancy());
  		}
  		executor.shutdown();
  	}
  
  }
  