Java【有与无】【参考】线程同步与锁

1.Synchronized【隐式

Java 内部使用monitor 也叫做监控锁或者内部锁来管理同步。这个monitor是绑定到对象上的。例如多线程调用同一个同步过的方法,这些方法的monitor都是同一个,而这个monitor是属于某个对象的。

所有隐式monitor都是想了可重入特性。可重入的意思是:锁是绑定到当前线程的,一个线程可以多次安全的获取到同一个锁而不会进入死锁。

private int count = 0;

// 线程不安全
private void increment() {
    count = count + 1;
}

// 线程安全
private void incrementSync() {
    synchronized (this) {
        count = count + 1;
    }
}

// 线程安全
private synchronized void incrementSync2() {
    count = count + 1;
}

// 线程安全
private static void synchronizedTest() {
    SynchronizedUtilTest test = new SynchronizedUtilTest();

    ExecutorService executor = Executors.newFixedThreadPool(2);
    IntStream.range(0, 10000).forEach(i -> executor.submit(test::incrementSync2));
    stop(executor);
    System.out.println(test.count);
}

2.ReentrantLock

重入锁

private static void reentrantLockTest() {
    // tryLock()是lock()的一个替代方法,这个方法不阻塞当前线程,我们可以根据这个方法的执行结果来决定是否允许访问共享数据
    SynchronizedUtilTest test = new SynchronizedUtilTest();

    ExecutorService executor = Executors.newFixedThreadPool(2);
    ReentrantLock lock = new ReentrantLock();

    // 线程会持有锁1秒钟
    executor.submit(() -> {
        lock.lock();
        try {
            test.count++;
            sleep(1);
        } finally {
            lock.unlock();
        }
    });
    // 线程获取了当前锁的各种状态
    executor.submit(() -> {
        System.out.println("Locked: " + lock.isLocked());
        System.out.println("Held by me: " + lock.isHeldByCurrentThread());
        boolean locked = lock.tryLock();
        System.out.println("Lock acquired: " + locked);
    });

    stop(executor);
    System.out.println(test.count);
}

3.ReadWriteLock

这种锁维护了一对锁,读锁写锁 

private static void readWriteLockTest() {
    // 读取任务必须等待写入任务完成才能开始;
    // 一旦写入任务完成,读取任务开始后,两个读取任务是并行执行的,不用等待其中一个执行完成
    SynchronizedUtilTest test = new SynchronizedUtilTest();

    ExecutorService executor = Executors.newFixedThreadPool(2);
    Map<String, String> map = new HashMap<>();
    ReadWriteLock lock = new ReentrantReadWriteLock();

    executor.submit(() -> {
        lock.writeLock().lock(); // 获取写入锁
        try {
            sleep(1);
            map.put("foo", "foo");
            map.put("bar", "bar");
        } finally {
            lock.writeLock().unlock(); // 写入锁释放
        }
    });

    Runnable readTask1 = () -> {
        lock.readLock().lock(); // 获取读入锁
        try {
            System.out.println(map.get("foo"));
            sleep(1);
        } finally {
            lock.readLock().unlock(); // 写入读释放
        }
    };

    Runnable readTask2 = () -> {
        lock.readLock().lock(); // 获取读入锁
        try {
            System.out.println(map.get("bar"));
            sleep(1);
        } finally {
            lock.readLock().unlock(); // 写入读释放
        }
    };

    executor.submit(readTask1);
    executor.submit(readTask1);
    executor.submit(readTask2);
    executor.submit(readTask2);

    stop(executor);
}

4.StampedLock

与ReadWriteLock相似
private static void stampedLockTest() {
    // 与ReadWriteLock相似
    ExecutorService executor = Executors.newFixedThreadPool(2);
    Map<String, String> map = new HashMap<>();
    StampedLock lock = new StampedLock();

    executor.submit(() -> {
        long stamp = lock.writeLock(); // 获取写锁,返回锁标识
        try {
            sleep(1);
            map.put("foo", "foo");
            map.put("bar", "bar");
        } finally {
            lock.unlockWrite(stamp); // 根据锁标识,释放写锁
        }
    });

    Runnable readTask1 = () -> {
        long stamp = lock.readLock(); // 获取读锁,返回锁标识
        try {
            System.out.println(map.get("foo"));
            sleep(1);
        } finally {
            lock.unlockRead(stamp); // 根据锁标识,释放读锁
        }
    };
    Runnable readTask2 = () -> {
        long stamp = lock.readLock(); // 获取读锁,返回锁标识
        try {
            System.out.println(map.get("bar"));
            sleep(1);
        } finally {
            lock.unlockRead(stamp); // 根据锁标识,释放读锁
        }
    };

    executor.submit(readTask1);
    executor.submit(readTask1);
    executor.submit(readTask2);
    executor.submit(readTask2);

    stop(executor);
}
乐观锁
private static void stampedLock2Test() {
    // 乐观锁
    ExecutorService executor = Executors.newFixedThreadPool(2);
    StampedLock lock = new StampedLock();

    executor.submit(() -> {
        long stamp = lock.tryOptimisticRead(); // 获取乐观锁, 返回锁标识;不会阻塞线程
        try {
            System.out.println("Optimistic Lock Valid: " + lock.validate(stamp)); // 访问任何共享可变变量后验证这个锁是否还处于合法状态
            sleep(1);
            System.out.println("Optimistic Lock Valid: " + lock.validate(stamp));
            sleep(2);
            System.out.println("Optimistic Lock Valid: " + lock.validate(stamp));
        } finally {
            lock.unlock(stamp); // 根据锁标识,释放乐观锁
        }
    });

    executor.submit(() -> {
        long stamp = lock.writeLock(); // 获取写锁,返回锁标识
        try {
            System.out.println("Write Lock acquired");
            sleep(2);
        } finally {
            lock.unlock(stamp); // 根据锁标识,释放写锁
            System.out.println("Write done");
        }
    });

    stop(executor);
}
读锁转换成写锁
private static void stampedLock3Test() {
    // 读锁转换成写锁
    SynchronizedUtilTest test = new SynchronizedUtilTest();

    ExecutorService executor = Executors.newFixedThreadPool(2);
    StampedLock lock = new StampedLock();

    executor.submit(() -> {
        long stamp = lock.readLock(); // 获取读锁, 返回锁标识
        try {
            if (test.count == 0) {
                stamp = lock.tryConvertToWriteLock(stamp); // 读锁转换成写锁,不破坏线程安全性;不会阻塞线程
                if (stamp == 0L) {
                    System.out.println("Could not convert to write lock");
                    stamp = lock.writeLock(); // 获取写锁, 返回锁标识
                }
                test.count = 23;
            }
            System.out.println(test.count);
        } finally {
            lock.unlock(stamp); // 根据锁标识,释放读锁
        }
    });

    stop(executor);
}

5.Semaphore

计数信号量

锁通常用来保证变量或者资源的独占性,而信号量可以维护整个权限集合。

private static void semaphoresTest() {
    // 信号量
    ExecutorService executor = Executors.newFixedThreadPool(10); // 最大并发执行10个任务

    Semaphore semaphore = new Semaphore(5); // 最大并发访问为5

    Runnable longRunningTask = () -> {
        boolean permit = false;
        try {
            permit = semaphore.tryAcquire(1, TimeUnit.SECONDS); // 尝试获取一个信号量
            if (permit) {
                System.out.println("Semaphore acquired");
                sleep(5);
            } else {
                System.out.println("Could not acquire semaphore");
            }
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        } finally {
            if (permit) {
                semaphore.release();  // 释放一个信号量
            }
        }
    };

    IntStream.range(0, 10).forEach(i -> executor.submit(longRunningTask));

    stop(executor);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

琴 韵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值