1. The description of the Lock

1.1 Java. Util. The locks. The Lock

1.2 Lock Interface Description

After the JDK. 5

  • Void lock() acquires the lock
  • Void unlock() Releases the lock
  • Void lockInterruptibly() Interrupts the lock preemption process and throws an exception
  • Boolean tryLock() Non-blocking lock acquisition

1.2 the implementation class

  • ReentrantLock indicates the ReentrantLock
public class ReentrantLock implements Lock, java.io.Serializable { public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }}Copy the code
  • ReentrantReadWriteLock Reentrant read/write lock (exclusive and shared)

2. Use the Lock

2.1 Code Examples

import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockSequence { private int value; Lock lock = new ReentrantLock(); Lock lock1 = new ReentrantLock(); @return */ public int getNext_1() {Lock lock1 = new ReentrantLock(); // If you write this to generate one lock each time, you should use the same lock in multiple threads. value = value ++; lock1.unlock(); // We can place the lock in a Finnaly block, so that the lock can be released when an exception occurs. } public int getNext() { lock.lock(); value = value ++; lock.unlock(); // We can place the lock in a Finnaly block, so that the lock can be released when an exception occurs. } public static void main(String[] args) { LockSequence s = new LockSequence(); new Thread(new Runnable() { @Override public void run() { while(true) { System.out.println(Thread.currentThread().getName() + " " + s.getNext()); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); new Thread(new Runnable() { @Override public void run() { while(true) { System.out.println(Thread.currentThread().getName() + " " + s.getNext()); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); new Thread(new Runnable() { @Override public void run() { while(true) { System.out.println(Thread.currentThread().getName() + " " + s.getNext()); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); }}Copy the code

1.3 the Lock to summarize

  • Using Lock is a convenient way to achieve fairness
  • Non-blocking acquisition lock tryLock
  • Acquire lockInterruptibly that can be interrupted
  • Timeout Acquire lock Acquire the lock at the specified time class

1.3 Summary of common thread safety processing methods

  • Synchronized does not need to acquire and release locks explicitly, simply
  • Volatile guarantees visibility, not atomicity
  • A Lock needs to be acquired and released in an explicit way. The complexity makes the code more flexible. A Lock is an interface, and its implementation class can be used as needed. It’s easy to see how much more powerful Lock wraps Synchronied.

2. Custom Lock (implement Lock)

The source code

import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; public class MyLock implements Lock { private boolean isLocked = false; private Thread lockBy = null; private int lockCount = 0; @Override public synchronized void lock() { // ... Thread currentThread = Thread.currentThread(); // Thread-0 while (isLocked && currentThread ! = lockBy) try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } isLocked = true; lockBy = currentThread; lockCount ++; // 1 2 } @Override public synchronized void unlock() { if(lockBy == Thread.currentThread()) { lockCount --; // 1 0 if(lockCount == 0) { notify(); isLocked = false; } } } @Override public void lockInterruptibly() throws InterruptedException { } @Override public boolean tryLock() { return false; } @Override public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { return false; } @Override public Condition newCondition() { return null; } } public class MyLockSequence { private MyLock lock = new MyLock(); private int value; public int getNext() { lock.lock(); value++; lock.unlock(); return value; } public static void main(String[] args) { MyLockSequence s = new MyLockSequence(); new Thread(new Runnable() { @Override public void run() { while(true) System.out.println(s.getNext()); } }).start(); new Thread(new Runnable() { @Override public void run() { while(true) System.out.println(s.getNext()); } }).start(); new Thread(new Runnable() { @Override public void run() { while(true) System.out.println(s.getNext()); } }).start(); new Thread(new Runnable() { @Override public void run() { while(true) System.out.println(s.getNext()); } }).start(); new Thread(new Runnable() { @Override public void run() { while(true) System.out.println(s.getNext()); } }).start(); } } import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; Public class MyLockDemo {//Lock Lock = new ReentrantLock(); MyLock lock = new MyLock(); Public void a() {lock.lock(); System.out.println("a"); b(); lock.unlock(); } public void b() { lock.lock(); System.out.println("b"); c(); lock.unlock(); } public void c() { lock.lock(); System.out.println("c"); lock.unlock(); } public static void main(String[] args) { MyLockDemo d = new MyLockDemo(); new Thread(new Runnable() { @Override public void run() { d.a(); } }).start(); // new Thread(new Runnable() { // // @Override // public void run() { // d.b(); // } // }).start(); }}Copy the code

Key notes:

  • Use WAIT and notify to control the thread state
  • Control reentrant and reentrant count by comparing the current thread to the current thread