directory

introduce

Synchronized modifies the execution order of a block

Lock provides a more flexible way to implement it

The lock interface

This thing is used in scenarios

Lock and lock release examples

Lock Common lock acquisition

tryLock()

Interrupt lock

newCondition()

Implementation class of the Lock interface: ReentrantLock main method

Already the lock sample

The lock sample

Results the log

TryLock lock

The results of

 lock.tryLock(1000,TimeUnit.SECONDS)

LockInterruptibly () responds to how interrupts are used

The results of

Condition interface use

The main implementation methods of the interface:

Condition implements a wait/notification mechanism

Multiple Condition instances implement the wait/notification mechanism

Condition implements sequential execution

ReadWriteLock

ReentrantReadWriteLock Describes the interface

Effect of synchronized

Implement read/write lock read sharing

Read/write lock write mutually exclusive

conclusion

Reentrant lock

Interruptible lock

Fair lock

Read-write lock

Let’s see the difference between locking and not locking

lock

Don’t lock



introduce

Java JDK1.5 used synchronized to implement the Lock, and 1.5 after the package and new Lock interface and related implementation classes to achieve the Lock function. The scope mechanism of synchronized methods and statements makes using monitor locks easier to program and helps avoid many common programming errors involving locks, but sometimes you need to handle locks in a more flexible way.

 

Synchronized modifies the execution order of a block

  • 1. The thread that acquires the lock completes the code block, and then releases the lock
  • 2. When thread execution is abnormal, the JVM causes the thread to release the lock automatically

 

Lock provides a more flexible way to implement it

LockInterruptibly tryLock () determines whether the lock is released to ryLock(Long time, TimeUnit Unit). (Time long, time type (milliseconds, (unlock newCondition() conditionCopy the code

 

The lock interface

Lock the original code, interface, the interface implementation class, has already ReentrantReadWriteLock. ReadLock, ReentrantReadWriteLock. WriteLock

public interface Lock {
    void lock();
    void lockInterruptibly() throws InterruptedException;
    boolean tryLock();
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    void unlock();
    Condition newCondition();
}
Copy the code

 

This thing is used in scenarios

  • Lock is just a normal code block
  • TryLock and arguments are thrown away when the business needs them and thrown away when they become obsolete
  • LockInterruptibly The lockInterruptibly lock is used in scenarios where a thread stops working on a task and sends a notification when it is finished.
  • NewCondition has great flexibility. For example, multiple Condition instances (object monitors) can be created in a Lock object. Thread objects can be registered in a given Condition, allowing selective thread notification. More flexibility in scheduling threads.

 

Lock and lock release examples

Lock Common lock acquisition

Lock lock=new ReentrantLock(); lock.lock(); Try {// process tasks}catch(Exception ex){}finally{lock.unlock(); // release the lock}Copy the code

 

tryLock()

Lock lock=new ReentrantLock(); If (lock.trylock ()) {try{// process the task}catch(Exception ex){}finally{lock.unlock(); // If you can't get the lock, do something else.Copy the code

The tryLock() method returns a value indicating that it was used to attempt to acquire the lock. It returns true on success or false on failure (i.e. the lock has been acquired by another thread), meaning that the method will return immediately anyway and will not wait until the lock is unavailable.

 

Interrupt lock

public void method() throws InterruptedException { Lock lock=new ReentrantLock(); lock.lockInterruptibly(); try { //..... } finally { lock.unlock(); }}Copy the code
  • When a thread acquires a lock, it is not interrupted by the interrupt() method. Because calling the interrupt() method alone cannot interrupt a running thread, only a blocking thread. Therefore, when a lock is obtained using the lockInterruptibly() method, if it is not obtained, the interrupt can be responded to only by waiting. Synchronized means that a thread that is waiting for a lock cannot be interrupted

 

newCondition()

Gets the wait notification component, which is bound to the current lock. The current thread can call its wait() method only after it has acquired the lock, and the current thread releases the lock.

 

Implementation class of the Lock interface: ReentrantLock main method

ReentrantLock(Boolean fair) // Create a ReentrantLock with a given fair policy int getHoldCount() Protected Thread getOwner() returns the Thread that currently holds the lock. If the lock is not held by any Thread, Return null protected Collection<Thread> getQueuedThreads() Int getQueueLength() // Returns an estimate of the number of threads waiting to acquire the lock. Protected Collection<Thread> getWaitingThreads(Condition Condition) // Returns a collection, Int getWaitQueueLength(Condition Condition) // Returns an estimate of the number of threads waiting for a given Condition associated with this lock HasQueuedThreads (Thread Thread) // Queries whether a given Thread is waiting to acquire the lock Boolean hasQueuedThreads() // queries whether some threads are waiting to acquire the lock Boolean Loves your work (Condition Condition) // Check whether some threads are waiting for a given Condition associated with this lock. Boolean isFair() // If this lock is set to true, Boolean isLocked() // Checks whether the lock is held by any thread. Void lock() // Retrieves the lock void LockInterruptibly () // If the current thread is not interrupted, the lock is acquired. Condition newCondition() // Returns the Condition instance used with this Lock instance Boolean tryLock() // Only if the Lock is not held by another thread when called, Boolean tryLock(long timeout, TimeUnit Unit) // If the lock is not held by another thread within a given wait time and the current thread is not interrupted, acquire the lock void unlock() // attempt to release the lockCopy the code

 

Already the lock sample

The lock sample

package com.superman.test; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockTest2 { public static void main(String[] args) { LockTask test = new LockTask(); for (int i = 0; i <6; I++) {// execute 6 threads new LockTaskThread(test).start(); }} static class LockTaskThread extends Thread{private LockTask lt; public LockTaskThread(LockTask lt){ this.lt=lt; } public void run(){ lt.insert(Thread.currentThread()); }} static class LockTask {private Lock Lock = new ReentrantLock(); public void insert(Thread thread){ lock.lock(); Try {system.out.println (thread.getName() + "lock "); for (int i = 0; i < 5; i++) { System.out.println("ThreadName=" + Thread.currentThread().getName() + (" " + (i + 1))); }} catch (Exception e) {} finally {system.out.println (thread.getName() + "release lock "); lock.unlock(); }}}}Copy the code

 

Results the log

1 ThreadName= thread-0 2 ThreadName= thread-0 3 ThreadName= thread-0 4 ThreadName= thread-0 ThreadName= thread-1 1 ThreadName= thread-1 2 ThreadName= thread-1 3 ThreadName= thread-1 4 ThreadName= thread-2 1 ThreadName= thread-2 2 ThreadName= thread-2 3 ThreadName= thread-2 4 ThreadName= thread-2 5 thread-2 releases the lock thread-3 obtains the lock ThreadName= thread-3 1 ThreadName= thread-3 2 ThreadName= thread-3 3 ThreadName= thread-3 4 ThreadName= thread-3 5 ThreadName= thread-3 5 ThreadName= thread-3 5 ThreadName= thread-3 5 ThreadName= thread-3 ThreadName= thread-4 2 ThreadName= thread-4 3 ThreadName= thread-4 4 ThreadName= thread-4 5 ThreadName= thread-4 The lock is released thread-5 the lock is obtained ThreadName=Thread-5 1 ThreadName=Thread-5 2 ThreadName=Thread-5 3 ThreadName=Thread-5 4 ThreadName=Thread-5 5 Thread-5 releases the lockCopy the code
  • This is a sequentially executed lock, one run after the next entry

TryLock lock

static class LockTask { private Lock lock = new ReentrantLock(); Public void insert(Thread Thread){if(lock.trylock ()) {try {system.out.println (thread.getName()+" get the lock "); for (int i = 0; i < 3; i++) { System.out.println("ThreadName=" + Thread.currentThread().getName() + (" " + (i + 1))); }} catch (Exception e) {}finally {system.out.println (thread.getName()+" release lock "); lock.unlock(); }} else {system.out.println (thread.getname ()+" lock failed "); }}}Copy the code

Make a judgment, get to execute, not get to discard

The results of

ThreadName= thread0 1 thread-5 failed to obtain the lock thread-1 failed to obtain the lock thread-2 failed to obtain the lock thread-4 failed to obtain the lock ThreadName= thread-0 1 thread-5 failed to obtain the lock ThreadName= thread-0 2 ThreadName= thread-0 3 Thread-0 releases the lockCopy the code

 

 lock.tryLock(1000,TimeUnit.SECONDS)

static class LockTaskThread extends Thread{ private LockTask lt; public LockTaskThread(LockTask lt){ this.lt=lt; } public void run(){ try { lt.insert(Thread.currentThread()); } catch (InterruptedException e) { e.printStackTrace(); } } } static class LockTask { private Lock lock = new ReentrantLock(); public void insert(Thread thread) throws InterruptedException{ if(lock.tryLock(1000,TimeUnit.SECONDS)) { try { System.out.println(thread.getName()+" lock "); for (int i = 0; i < 3; i++) { System.out.println("ThreadName=" + Thread.currentThread().getName() + (" " + (i + 1))); }} catch (Exception e) {}finally {system.out.println (thread.getName()+" release lock "); lock.unlock(); }} else {system.out.println (thread.getname ()+" lock failed "); }}}Copy the code

 

LockInterruptibly () responds to how interrupts are used

public class LockTest2 { private Lock lock = new ReentrantLock(); public static void main(String[] args) { LockTest2 test = new LockTest2(); MyThread thread1 = new MyThread(test); MyThread thread2 = new MyThread(test); thread1.start(); thread2.start(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } thread2.interrupt(); } public void insert(Thread thread) throws InterruptedException { lock.lockInterruptibly(); // Note that to properly interrupt the thread waiting for the lock, you must place the lock acquisition outside and throw InterruptedException try {system.out.println (thread.getName() + "Lock obtained "); long startTime = System.currentTimeMillis(); for (; ;) { if (System.currentTimeMillis() - startTime >= Integer.MAX_VALUE) break; }} finally {system.out.println (thread.currentThread ().getName() + "finally"); lock.unlock(); System.out.println(thread.getName() + "release lock "); } } static class MyThread extends Thread { private LockTest2 test; public MyThread(LockTest2 test) { this.test = test; } @Override public void run() { try { test.insert(Thread.currentThread()); } catch (InterruptedException e) {system.out.println (thread.currentThread ().getName() + "interrupted "); }}}}Copy the code

The results of

Thread0 acquired a lock and Thread1 was interruptedCopy the code

 

Condition interface use

  • The synchronized keyword, combined with wait() and notify/notifyAll(), implements the wait/notification mechanism, as does the ReentrantLock class, but with the aid of the Condition interface and newCondition(). Condition was introduced after JDK1.5, and it has great flexibility. For example, multiple Condition instances (object monitors) can be created in a Lock object. Thread objects can be registered in a given Condition. In this way, thread notification can be carried out selectively and thread scheduling is more flexible.
  • When notify/notifyAll() is used, the thread to be notified is selected by the JVM. The ReentrantLock class and Condition instance can be used to implement selective notification
  • The synchronized keyword is equivalent to a single Condition instance in the Lock object, to which all threads are registered. A notifyAll() method notifies all waiting threads, which is inefficient, whereas a Condition instance’s signalAll() method only wakes up all waiting threads registered in the Condition instance

The main implementation methods of the interface:

Void await() // causes the current thread to wait until it receives a signal or is interrupted. Boolean await(long time, TimeUnit unit) // Causes the current thread to wait until it receives a signal, is interrupted, or reaches the specified wait time. Long awaitNanos(long nanosTimeout) // Causes the current thread to wait until it receives a signal, is interrupted, or reaches the specified wait time. Void awaitUninterruptibly() // Causes the current thread to wait until it receives a signal. Boolean awaitUntil(Date deadline) // Causes the current thread to wait until it receives a signal, is interrupted, or reaches a specified deadline. Void signal() // Wakes up a waiting thread. Void signalAll() // Wake up all waiting threads.Copy the code

 

Condition implements a wait/notification mechanism

public class test1 { public static void main(String[] args) throws InterruptedException { MyService service = new MyService(); ThreadA a = new ThreadA(service); a.start(); Thread.sleep(3000); service.signal(); } static public class MyService { private Lock lock = new ReentrantLock(); public Condition condition = lock.newCondition(); public void await() { lock.lock(); Try {system.out.println ("await time: "+ system.currentTimemillis ()); condition.await(); System.out.println(" This is the statement after the condition.await() method, condition.signal() method before I am executed "); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void signal() { lock.lock(); Try {system.out.println ("signal time "+ system.currentTimemillis ()); condition.signal(); Thread.sleep(3000); System.out.println(" This is the statement after the condition.signal() method "); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } static public class ThreadA extends Thread { private MyService service; public ThreadA(MyService service) { this.service = service; } @Override public void run() { service.await(); }}}Copy the code

The lock must be released after the try block of signal is executed, and statements after condition.await() can be executed.

 

Multiple Condition instances implement the wait/notification mechanism

public class test1 { private Lock lock = new ReentrantLock(); private Condition conditionA = lock.newCondition(); private Condition conditionB = lock.newCondition(); public void awaitA() { lock.lock(); Try {system.out. println("begin awaitA time is "+ System.currentTimemillis () +" ThreadName=" + Thread.currentThread().getName()); conditionA.await(); System.out.println(" thread.currentTimemillis () + "thread.currentThread ().getName()); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void awaitB() { lock.lock(); Try {system.out.println ("begin awaitB time is "+ System.currentTimemillis () +" ThreadName=" + Thread.currentThread().getName()); conditionB.await(); Thread.out.println (" thread.currentTimemillis () + "thread.currentThread ().getName()); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void signalAll_A() { lock.lock(); Try {system.out.println ("signalAll_A time "+ System.currentTimemillis () +" ThreadName=" + Thread.currentThread().getName()); conditionA.signalAll(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void signalAll_B() { lock.lock(); Try {system.out.println ("signalAll_B time "+ System.currentTimemillis () +" ThreadName=" + Thread.currentThread().getName()); conditionB.signalAll(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public static void main(String[] args) throws InterruptedException { test1 service = new test1(); ThreadA a = new ThreadA(service); a.setName("A"); a.start(); ThreadB b = new ThreadB(service); b.setName("B"); b.start(); Thread.sleep(3000); service.signalAll_A(); } static public class ThreadA extends Thread { private test1 service; public ThreadA(test1 service) { this.service = service; } @Override public void run() { service.awaitA(); } } static public class ThreadB extends Thread { private test1 service; public ThreadB(test1 service) { this.service = service; } @Override public void run() { service.awaitB(); }}}Copy the code

Condition implements sequential execution

package com.superman.test; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class test1 { volatile private static int nextPrintWho = 1; Final private static ReentrantLock lock = new ReentrantLock(); // By default, ReentranLock uses an unfair lock. final private static Condition conditionA = lock.newCondition(); final private static Condition conditionB = lock.newCondition(); final private static Condition conditionC = lock.newCondition(); public static void main(String[] args) { Thread threadA = new Thread() { public void run() { lock.lock(); try { while (nextPrintWho ! = 1) { conditionA.await(); } for (int i = 0; i < 3; i++) { System.out.println("ThreadA" + (i + 1)); } nextPrintWho = 2; Conditionb. signalAll(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); }}}; Thread threadB = new Thread() { public void run() { lock.lock(); try { while (nextPrintWho ! = 2) { conditionB.await(); } for (int i = 0; i < 3; i++) { System.out.println("ThreadB" + (i + 1)); } nextPrintWho = 3; Condition.signalall (); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); }}}; Thread threadC = new Thread() { public void run() { lock.lock(); try { while (nextPrintWho ! = 3) { conditionC.await(); } for (int i = 0; i < 3; i++) { System.out.println("ThreadC" + (i + 1)); } nextPrintWho = 1; Conditiona. signalAll(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); }}}; Thread[] array1 = new Thread[5]; Thread[] array2 = new Thread[5]; Thread[] array3 = new Thread[5]; for (int i = 0; i < 5; i++) { array1[i] = new Thread(threadA); array2[i] = new Thread(threadB); array3[i] = new Thread(threadC); array1[i].start(); array2[i].start(); array3[i].start(); }}}Copy the code

After a thread has finished running, the next particular run is notified by the condition.signal()/ condition.signalall () methods, and so on.

 

ReadWriteLock

public interface ReadWriteLock {
    /**
     * Returns the lock used for reading.
     *
     * @return the lock used for reading
     */
    Lock readLock();

    /**
     * Returns the lock used for writing.
     *
     * @return the lock used for writing
     */
    Lock writeLock();
}
Copy the code

ReentrantReadWriteLock Implements the ReadWriteLock interface

ReentrantReadWriteLock Describes the interface

  • Read locks are shared, while write locks are mutually exclusive

Effect of synchronized

public class test1 { public static void main(String[] args) { final test1 test = new test1(); for (int i = 0; i <3; i++) { new Thread() { public void run() { test.get(Thread.currentThread()); } }.start(); } } synchronized public void get(Thread thread) { for (int i = 0; i < 2; I++) {system.out.println (thread.getname () + "reading "); } system.out.println (thread.getName() + "read "); }}Copy the code

The second task will not be executed until the first one is completed

Implement read/write lock read sharing

public class test1 { public static void main(String[] args) { final test1 test = new test1(); for (int i = 0; i < 3; i++) { new Thread() { public void run() { test.read(Thread.currentThread()); } }.start(); } } private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); public void read(Thread thread) { rwl.readLock().lock(); try { for (int i = 0; i < 3; I++) {system.out.println (thread.getname () + "reading "); } system.out.println (thread.getName() + "read "); } finally { rwl.readLock().unlock(); }}}Copy the code

Read at the same time, realize read sharing

 

Read/write lock write mutually exclusive

import java.util.concurrent.locks.ReentrantReadWriteLock; public class test1 { public static void main(String[] args) { final test1 test = new test1(); for (int i = 0; i < 3; i++) { new Thread() { public void run() { test.write(Thread.currentThread()); } }.start(); } } private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); public void write(Thread thread) { rwl.writeLock().lock(); try { for (int i = 0; i < 3; I++) {system.out.println (thread.getname () + "write "); } system.out.println (thread.getName() + "write complete "); } finally { rwl.writeLock().unlock(); }}}Copy the code

Writing is incompatible, and the next one cannot be executed until the last one has been executed

 

conclusion

Reentrant lock

If a lock is reentrant, it is called a reentrant lock. For example, synchronized and ReentrantLock are both reentrant locks. Method 2 does not need to apply for a new lock when synchronized changes method 1 to method 2 in the same class.

 

Interruptible lock

In Java, synchronized is not a breakable Lock and Lock is a breakable Lock. If thread A is executing the code in the lock, and thread B is waiting to acquire the lock, maybe because the waiting time is too long, thread B doesn’t want to wait and wants to do other things first, we can tell it to interrupt itself or interrupt it in another thread, this is called interruptible lock.

Fair lock

Fair locking means that locks are acquired in the order in which they are requested. For example, if there are multiple threads waiting for a lock, when the lock is released, the thread that waited the longest (the thread that requested it first) gets the lock. This is a fair lock. An unfair lock is one in which there is no guarantee that the lock is acquired in the order in which it was requested. This may result in one or more threads never acquiring the lock. In Java, synchronized is an unfair lock that does not guarantee the order in which waiting threads acquire the lock. For ReentrantLock and ReentrantReadWriteLock, it is an unfair lock by default, but can be set to a fair lock. Set the constructor to false for a fair lock, true for an unfair lock, and default for an unfair lock

Read-write lock

Read/write locks divide access to a resource (such as a file) into two locks, a read lock and a write lock. Because of the read-write lock, the read operation between multiple threads does not conflict. ReadWriteLock is a read/write lock. It is an interface. ReentrantReadWriteLock implements this interface. Read locks can be obtained by readLock() and write locks by writeLock().

 

 

Let’s see the difference between locking and not locking

lock

package com.superman.test;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class testV {
	private static Lock lock = new ReentrantLock();
	public static void main(String[] args) {
		System.out.println("start");
		a1 a = new a1();
		for (int i = 0; i < 5; i++) {
			final int now = i;
			new Thread(new Runnable() {
				@Override
				public void run() {
					lock.lock();
					a.setName(now+"task");
					a.execute();
					try {
						Thread.sleep(12);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					lock.unlock();
				}
			}).start();
		}
		System.out.println("end");
	}
	
}
class a1 {
	private String name = "";
	public void setName(String name){this.name=name;}
	private Lock lock = new ReentrantLock();
	public void execute(){
		lock.lock();
		for (int i = 0; i <5; i++) {
			System.out.println(name+" run :"+i);
		}
		lock.unlock();
	}
}
Copy the code

The lock internal variable name has not been replaced ok

 

 

Don’t lock

package com.superman.test;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class testV {
	private static Lock lock = new ReentrantLock();
	public static void main(String[] args) {
		System.out.println("start");
		a1 a = new a1();
		for (int i = 0; i < 5; i++) {
			final int now = i;
			new Thread(new Runnable() {
				@Override
				public void run() {
//					lock.lock();
					a.setName(now+"task");
					a.execute();
					try {
						Thread.sleep(12);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
//					lock.unlock();
				}
			}).start();
		}
		System.out.println("end");
	}
	
}
class a1 {
	private String name = "";
	public void setName(String name){this.name=name;}
	private Lock lock = new ReentrantLock();
	public void execute(){
		lock.lock();
		for (int i = 0; i <5; i++) {
			System.out.println(name+" run :"+i);
		}
		lock.unlock();
	}
}
Copy the code

Without locking, the internal convenience name equals zero is replaced with a lot of three and that’s the difference between locking and not locking, which is kind of crazy

 

 

 

 

 

 

 

ok

 

 

 

 

 

Continuously updated