多线程常见锁的基本用法

举报
桃花键神 发表于 2022/03/21 22:12:13 2022/03/21
【摘要】 CountDownLatch**官方解释:**一种同步辅助,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成countDownLatch用给定的计数进行初始化。由于对countDown方法的调用,await方法会阻塞直到当前计数达到0,之后所有等待的线程都会被释放,所有后续的await调用都会立即返回。这是一个一次性现象——计数不能重置。如果需要重置计数的版本,可以考虑使用Cyc...

CountDownLatch

**官方解释:**一种同步辅助,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成countDownLatch用给定的计数进行初始化。由于对countDown方法的调用,await方法会阻塞直到当前计数达到0,之后所有等待的线程都会被释放,所有后续的await调用都会立即返回。这是一个一次性现象——计数不能重置。如果需要重置计数的版本,可以考虑使用CyclicBarrier。countDownLatch是一个通用的同步工具,可以用于多种目的。用一个计数初始化的CountDownLatch作为一个简单的开/关闩锁,或gate:所有调用await的线程在gate处等待,直到它被调用countDown的线程打开。可以使用初始化为N的CountDownLatch使一个线程等待,直到Nthreads完成某些操作,或者某些操作已经完成N次。CountDownLatch的一个有用属性是,它不要求调用countDown的线程在继续之前等待计数达到0,它只是阻止任何线程继续等待,直到所有线程都可以通过。
案例一、

package duoxiancheng2;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * @author yeqv
 * @program A2
 * @Classname T2
 * @Date 2022/2/8 8:38
 * @Email w16638771062@163.com
 */
public class T2 {
    //CountDownLatch
    CountDownLatch latch = new CountDownLatch(1);

    public static void main(String[] args) {

        T2 t = new T2();
        new Thread(() -> t.a(), "A").start();
        new Thread(() -> t.b(), "B").start();
    }

    void a() {
        System.out.println(Thread.currentThread().getName() + "已启动");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        latch.countDown();
        System.out.println(Thread.currentThread().getName() + "已结束");


    }

    void b() {
        System.out.println(Thread.currentThread().getName() + "已启动");
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "已结束");

    }
}

**结果:**线程A,B启动。线程A在执行,线程B在等待
在这里插入图片描述
当线程A完成操作开锁之后,线程B开始执行(这里是某组操作完成时,也就是执行了countDown()方法。不是说线程A执行完。可能执行到中间就已经开锁了)
在这里插入图片描述

ReentrantLock

ReentrantLock 最大的特点公平锁
即哪个线程等待的时间最长优先执行
ReentrantLock常常对比着synchronized来分析,我们先对比着来看然后再一点一点分析。
(1)synchronized是独占锁,加锁和解锁的过程自动进行,易于操作,但不够灵活。ReentrantLock也是独占锁,加锁和解锁的过程需要手动进行,不易操作,但非常灵活。

(2)synchronized可重入,因为加锁和解锁自动进行,不必担心最后是否释放锁;ReentrantLock也可重入,但加锁和解锁需要手动进行,且次数需一样,否则其他线程无法获得锁。

(3)synchronized不可响应中断,一个线程获取不到锁就一直等着;ReentrantLock可以相应中断。

public class T3 {
    Lock lock = new ReentrantLock(true);//设置为true公平锁,效率低但公平

    void m() {
        for (int i = 0; i <= 20; i++) {
            lock.lock();
            System.out.println(Thread.currentThread().getName());
            try{
                TimeUnit.SECONDS.sleep(1);
            }catch(Exception e){
                e.printStackTrace();
            }
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        var t = new T3();
        new Thread(t::m,"T1").start();
        new Thread(t::m,"T2").start();
        new Thread(t::m,"T3").start();
        new Thread(t::m,"T4").start();
    }
}

ReadWriteLock

ReadWriteLock也是一个接口,提供了readLock和writeLock两种锁的操作机制,一个资源可以被多个线程同时读,或者被一个线程写,但是不能同时存在读和写线程。
假设在程序中定义一个共享的数据结构用作缓存,它大部分时间提供读服务(例如:查询和搜索),而写操作占有的时间很少,但是写操作完成之后的更新需要对后续的读服务可见。
特性:
读-读不互斥
读-写互斥
写-写互斥
案例、

public class TestReadWriteLock{
    public static void main(String[] args){
        ReadWriteLockDemo rw = new ReadWriteLockDemo();

        // 一个线程进行写
        new Thread(new Runnable(){
            public void run(){
                rw.set((int)(Math.random()*100));
            }
        },"Write:").start();


        // 100个线程进行读操作
        for(int i=0; i<100; i++){
            new Thread(new Runnable(){
                public void run(){
                rw.get();
                }
            },"Read:").start();
        }
    }
}
 
class ReadWriteLockDemo{
	private int number = 0;
	private ReadWriteLock lock = new ReentrantReadWriteLock();
	// 读
	public void get(){
		lock.readLock().lock(); // 上锁
        try{
        	System.out.println(Thread.currentThread().getName()+":"+number);
        }finally{
        	lock.readLock().unlock(); // 释放锁
        }
	}
    // 写
    public void set(int number){
        lock.writeLock().lock();
        try{
        	System.out.println(Thread.currentThread().getName());
        	this.number = number;
        }finally{
        	lock.writeLock().unlock();
        }
    }
}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。