Synchronized

  1. 概念:
    重量级锁、重入锁、jvm 级别锁
    使用:方法:ACC_SYNCHRONIZED、代码块 monitorenter\monitorexit
    jvm 监视器
  2. 范围:方法和代码块(对象锁和类锁):
  • 对于普通同步方法,锁是当前实例对象。 对于静态同步方法,锁是当前类的 Class 对象。 对于同步方法块,锁是 Synchonized
    括号里配置的对象。
  1. 场景:

资源竞争

  1. Lock&ReentrantLock 写法:
try {
   
 lock.lock();
} finally {
   
 lock.unlock();
}
  • void lock() 获取锁,调用该方法当前线程将会获取锁,当锁获取后,该方法将返回。
  • void lockInterruptibly() throws InterruptedException 可中断获取锁,与 lock()方法不同之处在于该方
  • ***响应中断,即在锁的获取过程中可以中断当前线程
  • boolean tryLock() 尝试非阻塞的获取锁,调用该方法立即返回,true 表示获取到锁
  • boolean tryLock(long time,TimeUnit unit) throws InterruptedException 超时获取锁,以下情况会返回:
  • 时间内获取到了锁,时间内被中断,时间到了没有获取到锁。
  • void unlock() 释放锁
  1. 统计:
    java.util.concurrent.locks.ReentrantLock#getHoldCount
    java.util.concurrent.locks.ReentrantLock#getQueuedThreads

  2. Synchronized 和 ReentrantLock 对比:

  • Synchronized:jvm 层级的锁 自动加锁自动释放锁
  • Lock:依赖特殊的 cpu 指令,代码实现、手动加锁和释放锁、Condition(生产消费模式)
  • ReentrantReadWriteLock 读写锁
  • 细粒度问题 ,读是共享的、写是独占的
  • java8 增加了对读写锁的优化:StampedLock
  1. 实例代码
  • static Lock可以锁注当前类 非静态的只能锁住当前类的实例对象
package com.itcode.;

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

/** * @author 夏天 * @date 2020年10月29日 22:32 */
public class ReentrantLock01 implements Runnable {
   
    private static int i = 0;
    static Lock lock = new ReentrantLock();

    private void add() {
   
        lock.lock();
        try {
   
            for (int i1 = 0; i1 < 5000; i1++) {
   
                i++;
            }
        } finally {
   
            lock.unlock();
        }
    }

    @Override
    public void run() {
   
        add();
    }

    public static void main(String[] args) throws InterruptedException {
   
        for (int j = 0; j < 20; j++) {
   
            i = 0;
            ReentrantLock01 sync01 = new ReentrantLock01();
            ReentrantLock01 sync02 = new ReentrantLock01();
            Thread t1 = new Thread(sync01);
            Thread t2 = new Thread(sync02);
            t1.start();
            t2.start();
            t1.join();
            t2.join();
            System.out.println(i);
        }
    }

}

Lock之tryLock

使用方法:

try {
   
	if(lock.tryLock());
} finally {
   
	//获取到锁在释放 如果不加条件判断 获取不到锁也会进行释放 会抛出异常IllegalMonitorStateException
	if (lock.isHeldByCurrentThread()) {
   
		lock.unlock();
	}
}
  1. tryLock()方法是有返回值的,它表示用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false,这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待。
  1. boolean tryLock(long timeout, TimeUnit unit) :
    参数1 等待时间,参数2 时间单位
    等待指定时间如果还获取不到锁返回false

实例代码:

package com.itcode.;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/** * @author 夏天 * @date 2020年10月29日 22:32 */
public class ReentrantLock02 implements Runnable {
   
    private static int i = 0;
    ReentrantLock lock = new ReentrantLock();


    @Override
    public void run() {
   
        try {
   
            if (lock.tryLock(4, TimeUnit.SECONDS)) {
   
                System.out.println(Thread.currentThread().getName() + "获取");
                Thread.sleep(6000);
            } else {
   
                System.out.println(Thread.currentThread().getName() + "获取锁失败");
            }
        } catch (InterruptedException e) {
   
            e.printStackTrace();
        } finally {
   
            //注意 不加这个会报错 IllegalMonitorStateException 没有锁无法解锁
            if (lock.isHeldByCurrentThread()) {
   
                lock.unlock();
            }
        }

    }

    public static void main(String[] args) throws InterruptedException {
   
        ReentrantLock02 reentrantLock02 = new ReentrantLock02();
        Thread t1 = new Thread(reentrantLock02);
        Thread t2 = new Thread(reentrantLock02);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }
}

ReentrantReadWriteLock 读写锁

细粒度问题 ,读是共享的、写是独占的

package com.itcode.;

import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/** * @author 夏天 * @date 2020年10月29日 22:42 * 可以同时读 上了写锁后就不可以读了 */
public class ReadWriterLockTest {
   

    ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
    ReentrantReadWriteLock.ReadLock readLock = lock.readLock();

    public String query() {
   
        readLock.lock();
        try {
   
            Thread.sleep(50);

            System.out.println("读数据");
            return "成功";
        } catch (InterruptedException e) {
   
            e.printStackTrace();
            return "成功";
        } finally {
   
            readLock.unlock();
        }
    }

    public void save() {
   
        writeLock.lock();
        try {
   
            System.out.println("保存数据");
            Thread.sleep(2000);
        } catch (InterruptedException e) {
   
            e.printStackTrace();
        } finally {
   
            writeLock.unlock();
        }
    }

    /** * 读50次 */
    int readCount = 50;
    /** * 写5次 */
    int writeCount = 5;

    public static void main(String[] args) throws InterruptedException, ExecutionException {
   
        ReadWriterLockTest readWriterLockTest = new ReadWriterLockTest();
        //new Thread(() -> {
   
        // while (true) {
   
        // readWriterLockTest.query();
        // }
        //}).start();
        //new Thread(() -> {
   
        // while (true) {
   
        // try {
   
        // readWriterLockTest.save();
        // } catch (InterruptedException e) {
   
        // e.printStackTrace();
        // }
        // }
        //}).start();
        CompletableFuture<String> queryFuture = CompletableFuture.supplyAsync(() -> {
   
            while (readWriterLockTest.readCount-- > 0) {
   
                readWriterLockTest.query();
            }
            return "查询完成";
        });
        CompletableFuture<String> saveFuture = CompletableFuture.supplyAsync(() -> {
   
            while (readWriterLockTest.writeCount-- > 0) {
   
                readWriterLockTest.save();
            }
            return "保存完成";
        });
        //等待所有线程结束 无法接受返回值 ,接收返回值使用anyOf
        CompletableFuture.allOf(queryFuture, saveFuture).get();
    }
}