synchronized被称为隐式锁,会自动获取释放锁,是非公平锁;Lock被称为显示锁,需要显示的手动获取释放锁,可以设置是否为公平锁。
Lock与synchronized一样可以实现线程同步,但比synchronized更强大,粒度更小,更灵活。
lock()
获取锁。unlock()
释放锁。显示锁的基本使用。
public class Demo { public static void main(String[] args) { Task task = new Task(); new Thread(task).start(); new Thread(task).start(); } } class Task implements Runnable { private Lock lock = new ReentrantLock(); @Override public void run() { lock.lock(); try { Thread.sleep(3000L); System.out.println(Thread.currentThread().getName() + " hello world"); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } }
非阻塞式获取锁。
lock()
是阻塞锁。tryLock()
是非阻塞锁,当锁被占用时,可以执行其他任务;tryLock()
支持超时时间,在指定时间内可以获取锁返回true,否则返回false。public class Demo { public static void main(String[] args) { Task task = new Task(); new Thread(task).start(); new Thread(task).start(); } } class Task implements Runnable { private Lock lock = new ReentrantLock(); @Override public void run() { if (lock.tryLock()) { try { Thread.sleep(3000L); System.out.println(Thread.currentThread().getName() + ": hello world"); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } else { System.out.println(Thread.currentThread().getName() + ": 锁被占用,执行其他任务!"); } } }
不可中断等待锁的线程:
public class Demo { public static void main(String[] args) { Task task = new Task(); Thread t1 = new Thread(task); Thread t2 = new Thread(task); t1.start(); t2.start(); try { Thread.sleep(1000L); } catch (InterruptedException e) { e.printStackTrace(); } //中断线程 t2.interrupt(); } } class Task implements Runnable { private Lock lock = new ReentrantLock(); @Override public void run() { lock.lock(); try { Thread.sleep(3000L); System.out.println(Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } }
输出:
java.lang.InterruptedException: sleep interrupted at java.base/java.lang.Thread.sleep(Native Method) at com.example.lib_java.Task.run(Demo.java:35) at java.base/java.lang.Thread.run(Thread.java:834) Thread-0
可中断等待锁的线程:
public class Demo { public static void main(String[] args) { Task task = new Task(); Thread t1 = new Thread(task); Thread t2 = new Thread(task); t1.start(); t2.start(); try { Thread.sleep(1000L); } catch (InterruptedException e) { e.printStackTrace(); } //中断线程 t2.interrupt(); } } class Task implements Runnable { private Lock lock = new ReentrantLock(); @Override public void run() { try { lock.lockInterruptibly(); } catch (InterruptedException e) { System.out.println(Thread.currentThread().getName() + "被中断"); return; } try { Thread.sleep(3000L); System.out.println(Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } }
输出:
Thread-1被中断 Thread-0
Condition的用法基本与synchronized的等待唤醒基本一致。
synchronized | Condition |
---|---|
wait() | await() |
wait(long timeout) | await(long time, TimeUnit unit) |
notify() | signal() |
notifyAll() | signalAll() |
public class Demo { public static void main(String[] args) { Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); Task task = new Task(lock, condition); new Thread(task).start(); } } class Task implements Runnable { private Lock lock; private Condition condition; public Task(Lock lock, Condition condition) { this.lock = lock; this.condition = condition; } @Override public void run() { lock.lock(); try { //等待 condition.await(); System.out.println("hello world"); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } }
说明:线程处于等待阶段,“hello world”一直没有输出。
public class Demo { public static void main(String[] args) { Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); Task task = new Task(lock, condition); new Thread(task).start(); try { Thread.sleep(1000L); } catch (InterruptedException e) { e.printStackTrace(); } lock.lock(); //唤醒 condition.signal(); lock.unlock(); } } class Task implements Runnable { private Lock lock; private Condition condition; public Task(Lock lock, Condition condition) { this.lock = lock; this.condition = condition; } @Override public void run() { lock.lock(); try { //等待 condition.await(); System.out.println("hello world"); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } }
说明:线程进入等待阶段,1秒后被唤醒,“hello world”被输出。
public class Demo { public static void main(String[] args) { Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); Task task = new Task(lock, condition); new Thread(task).start(); new Thread(task).start(); new Thread(task).start(); try { Thread.sleep(1000L); } catch (InterruptedException e) { e.printStackTrace(); } lock.lock(); //唤醒所有等待 condition.signalAll(); lock.unlock(); } } class Task implements Runnable { private Lock lock; private Condition condition; public Task(Lock lock, Condition condition) { this.lock = lock; this.condition = condition; } @Override public void run() { lock.lock(); try { condition.await(); System.out.println("hello world"); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } }
说明:1秒后,三个线程都被唤醒,输出了3个“hello world”。
ReentrantReadWriteLock.ReadLock
。ReentrantReadWriteLock.WriterLock
。public class Demo { public static void main(String[] args) { Task task = new Task(); Thread t1 = new Thread(task, "线程一"); Thread t2 = new Thread(task, "线程二"); Thread t3 = new Thread(task, "线程三"); t1.start(); t2.start(); t3.start(); } } class Task implements Runnable { private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(true); private Lock readLock = readWriteLock.readLock(); @Override public void run() { readLock.lock(); try { Thread.sleep(3000L); System.out.println(Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } finally { readLock.unlock(); } } }
说明:同时输出三条内容,说明三个线程同时拿到锁,所以读锁是共享的。
public class Demo { public static void main(String[] args) { Task task = new Task(); Thread t1 = new Thread(task, "线程一"); Thread t2 = new Thread(task, "线程二"); Thread t3 = new Thread(task, "线程三"); t1.start(); t2.start(); t3.start(); } } class Task implements Runnable { private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(true); private Lock writeLock = readWriteLock.writeLock(); @Override public void run() { writeLock.lock(); try { Thread.sleep(3000L); System.out.println(Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } finally { writeLock.unlock(); } } }
说明:依次输出三个线程的信息,说明三个线程是依次获取锁,所以写锁是独占的。
public class Demo { public static void main(String[] args) { //数据存储容器 RWDictionary dictionary = new RWDictionary(); //写任务 WriteTask writeTask = new WriteTask(dictionary); //读任务 ReadTask readTask = new ReadTask(dictionary); Thread write1 = new Thread(writeTask, "写入线程一"); Thread write2 = new Thread(writeTask, "写入线程二"); Thread write3 = new Thread(writeTask, "写入线程三"); Thread read1 = new Thread(readTask, "读取线程一"); Thread read2 = new Thread(readTask, "读取线程二"); Thread read3 = new Thread(readTask, "读取线程三"); write1.start(); write2.start(); write3.start(); read1.start(); read2.start(); read3.start(); } } /** * 写任务 */ class WriteTask implements Runnable { private RWDictionary dictionary; public WriteTask(RWDictionary dictionary) { this.dictionary = dictionary; } @Override public void run() { int i = 0; while (true) { try { Thread.sleep(1000L); } catch (InterruptedException e) { e.printStackTrace(); } String name = Thread.currentThread().getName(); dictionary.put("hello", name + "---" + i++); } } } /** * 读任务 */ class ReadTask implements Runnable { private RWDictionary dictionary; public ReadTask(RWDictionary dictionary) { this.dictionary = dictionary; } @Override public void run() { while (true) { try { Thread.sleep(1000L); } catch (InterruptedException e) { e.printStackTrace(); } String[] keys = dictionary.allKeys(); for (String key : keys) { Object value = dictionary.get(key); System.out.println(key + ":" + value); } } } } /** * 数据管理容器 */ class RWDictionary { //存储数据 private final HashMap<String, Object> map = new HashMap<>(); //读写锁 private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(true); //读锁 private final Lock r = readWriteLock.readLock(); //写锁 private final Lock w = readWriteLock.writeLock(); /** * 获取数据 */ public Object get(String key) { r.lock(); try { return map.get(key); } finally { r.unlock(); } } /** * 获取所有键 */ public String[] allKeys() { r.lock(); try { return map.keySet().toArray(new String[0]); } finally { r.unlock(); } } /** * 写入数据 */ public Object put(String key, Object value) { w.lock(); try { return map.put(key, value); } finally { w.unlock(); } } /** * 清理所有数据 */ public void clear() { w.lock(); try { map.clear(); } finally { w.unlock(); } } }
输出:
hello:写入线程一---193 hello:写入线程一---193 hello:写入线程一---193 hello:写入线程二---194 hello:写入线程二---194 hello:写入线程二---194 hello:写入线程一---195 hello:写入线程一---195 hello:写入线程一---195 hello:写入线程一---196 hello:写入线程一---196 hello:写入线程一---196