多线程试题案例2

1、实现多个线程,有一个线程收尾工作

CyclicBarrier

public class Test5 {

    CyclicBarrier bar = new CyclicBarrier(3,() -> System.out.println("大家到齐了,开饭了"));

    public static void main(String[] args) {
        // 实现多个线程,有一个线程收尾工作
        // 三个人一起吃饭,到齐开饭

        var t = new Test5();
        new Thread(() -> t.eat(6),"李四").start();
        new Thread(() -> t.eat(2),"李四").start();
        new Thread(() -> t.eat(8),"李四").start();

    }

    void eat(int t){
        System.out.println(Thread.currentThread().getName() + "开始动身...");
        try {
            TimeUnit.SECONDS.sleep(t);
            System.out.println(Thread.currentThread().getName() + "到达。");
            bar.await();
            // bar.await(6,TimeUnit.SECONDS);
        } catch (InterruptedException e){
            e.printStackTrace();
        } catch (BrokenBarrierException e){
            e.printStackTrace();
        }
    }
}

实现效果:

在这里插入图片描述

2、ReentrantLock 公平锁

ReentranLock常常对比着synchronized来分析,我们先对比着来看然后再一点一点分析。

	(1)synchronized是独占锁,加锁和解锁的过程自动进行,易于操作,但不够灵活。
	ReentrantLock也是独占锁,加锁和解锁的过程需要手动进行,不易操作,但非常灵活。
	
	(2)synchronized可重入,因为枷锁和解锁自动进行,不必担心最后是否释放锁;
ReentrantLock也可重入,但加锁和解锁需要手动进行,且次数需一样,否则其他线程无法获得锁。

	(3)synchronized不可响应中断,一个线程获取不到锁就一直等着;ReentrantLock可以响应中断。
	
	ReentrantLock好像比synchronized关键字没好太多,我们再去看看synchronized所没有的,一个
最主要的就是ReentrantLock还可以实现公平锁机制。什么叫公平锁讷?也就是在锁上等待时间最长
的线程将获得锁的使用权。通俗的理解就是谁排队时间最长谁先执行获取锁。

在这里插入图片描述

公平锁

在这里插入图片描述

public class ReentrantLockTest3 {

    Lock lock = new ReentrantLock();

    public static void main(String[] args) {
        var t = new ReentrantLockTest3();
        new Thread(t::m1,"t1").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e){
            e.printStackTrace();
        }
        new Thread(t::m2,"t2").start();

    }

    void m1(){
        lock.lock();
        for (int i = 0; i < 10; i++) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e){
                e.printStackTrace();
            }
            System.out.println(i);
        }
        lock.unlock();
    }

    void m2(){
        lock.lock();
        System.out.println("m2()...");
        lock.unlock();
    }
}
public class ReentrantLockTest4 {

    Lock lock = new ReentrantLock();

    public static void main(String[] args) {
        var t = new ReentrantLockTest4();
        new Thread(t::m1,"T1").start();
        Thread t2 = new Thread(t::m2,"T2");
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e){
            e.printStackTrace();
        }
        t2.start();
        t2.interrupt();
        System.out.println(Thread.activeCount());

    }

    void m1(){
        lock.lock();
        System.out.println("线程1启动");
        try {
            TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    void m2(){
        try {
            lock.lockInterruptibly();
            System.out.println("线程2终于打断了");
        } catch (InterruptedException e){
            System.out.println("编程2...");
        } finally {
            if (lock.tryLock())
                lock.unlock();
            System.out.println("线程2结束了");
            System.exit(0);
        }
    }
}
public class ReentrantLockTest5 {

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

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

    }

    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();
        }
    }
}

3、多个线程使用数量有限的资源

	Semaphore是一种基于计数的信号量。它可以设定一个阀值,基于此,多个线程竞争获取许可信号,
做自己的申请后归还,超过阀值后,线程申请许可信号将会被阻塞。
	Semaphore可以用来构建一些对象池,资源池之类的,比如数据库连接池,我们也可以创建计数
为1的Semaphore,将其作为一种类似互斥锁的机制,这也叫二元信号量,表示两种互斥状态。
public class SemaphoreTest1 {

    // 定义semaphore实例,设置许可数为10,即停车位为2个
    Semaphore semaphore = new Semaphore(2);

    public static void main(String[] args) {
        SemaphoreTest1 t = new SemaphoreTest1();
        new Thread(t::stop,"预A-SY281").start();
        new Thread(t::stop,"预B-SY666").start();
        new Thread(t::stop,"预C-SY777").start();
        new Thread(t::stop,"预D-SY888").start();
        new Thread(t::stop,"预E-SY999").start();
        new Thread(t::stop,"预F-SY595").start();
        new Thread(t::stop,"预G-SY317").start();

    }

    void stop(){
        String t = Thread.currentThread().getName();
        try {
            System.out.println(t + ":尝试进入停车场...");
            // 尝试获取许可,如果没有,则等待
            semaphore.acquire();
            // 模拟停车
            long time = (long) (Math.random() * 50 + 10);
            System.out.println(t + ":进入了停车场,停车" + time + "秒...");
            TimeUnit.SECONDS.sleep(time);
        } catch (InterruptedException e){
            e.printStackTrace();
        } finally {
            System.out.println(t + ":开始驶离停车场...");
            // 释放许可
            semaphore.release();
            System.out.println(t + ":离开了停车场!");
        }
    }
}

实现效果:

在这里插入图片描述

public class Semaphore implements java.io.Serializable{
    // 最多支持N个资源访问
    public Semaphore(int permits);
    
    // 获取可用的资源
    // 如果可用,信号量内部的资源个数减掉1
    // 如果没有可用资源线程会阻塞在该方法中,不能结束该方法,不能返回,直到有可用的资源为止
    public void acquire() throws InterruptedException;
    
    // 当前可用的资源个数,permits - availablePermits() = 正在使用的资源个数
    public int availablePermits();
    
    // 释放资源,释放后信号量内部的资源个数会增加1
    // 如果有被阻塞的线程,释放后会唤醒一个线程去获取资源
    // acquire() 和 release() 要成对使用,一半release() 放在finally代码块中
    public void release();
}

在这里插入图片描述

public class SemaphoreTest2 {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3);
        for (int i = 1; i <= 10; i++) {
            new Thread(new MyRunnable(semaphore),"第" + i + "个人").start();
        }

    }

    static class MyRunnable implements Runnable{
        private Semaphore semaphore;
        public MyRunnable(Semaphore semaphore){
            this.semaphore = semaphore;
        }

        @Override
        public void run() {
            String name = Thread.currentThread().getName();
            int availablePermits = semaphore.availablePermits();
            if (availablePermits > 0){
                System.out.println(name + "无人,可用");
            } else {
                System.out.println(name + "有人,请排队。。。\t");
            }

            try {
                // 如果没有拿到资源将一直等待,直到有人释放,拿到资源
                semaphore.acquire();
                System.out.println(name + "轮到我了");
                // 模拟使用时间
                Thread.sleep(1000);
                System.out.println(name + "使用完毕\t");
            } catch (InterruptedException e){

            } finally {
                // 使用完释放资源
                semaphore.release();
            }
        }
    }
}

实现效果:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值