备战2022春招-java-day4

9 篇文章 0 订阅

java

  1. 阻塞队列:
    在这里插入图片描述
    • 当阻塞队列是空时,从队列中获取元素的操作将会被阻塞
    • 当阻塞队列是满时,往队列里添加元素的操作将会被阻塞
    • 在多线程领域:所谓阻塞,在某些情况下会挂起线程(即阻塞),一旦条件满足,被挂起的线程又会自动被唤醒
    • 为什么需要BlockingQueue?好处是我们不需要关心什么时候需要阻塞线程,什么时候需要唤醒线程,因为这一切BlockingQueue都给你一手包办了
    • 分类:
      • ArrayBlockingQueue: 由数组结构组成的有界阻塞队列。
      • LinkedBlockingQueue: 由链表结构组成的有界(但大小默认值为Integer.MAX_VALUE)阻塞队列。
      • PriorityBlockingQueue: 支持优先级排序的无界阻塞队列。
      • DeleyQueue: 使用优先级队列实现的延迟无界阻塞队列。
      • SynchronousQueue(同步队列): 不存储元素的阻塞队列,也即单个元素的队列。(生产一个,消费一个)
      public class SynchronousQueueDemo {
          public static void main(String[] args) {
              BlockingQueue<String> syncQueue = new SynchronousQueue<String>();
      
              new Thread(() -> {
                  try {
                      System.out.println(Thread.currentThread().getName() + "\t" + "put 1");
                      syncQueue.put("1");
                      System.out.println(Thread.currentThread().getName() + "\t" + "put 2");
                      syncQueue.put("2");
                      System.out.println(Thread.currentThread().getName() + "\t" + "put 3");
                      syncQueue.put("3");
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }, "AAA").start();
      
              new Thread(() -> {
                  try {
                      TimeUnit.SECONDS.sleep(3);
                      System.out.println(Thread.currentThread().getName() + "\t"+ syncQueue.take());
                      TimeUnit.SECONDS.sleep(3);
                      System.out.println(Thread.currentThread().getName() + "\t" + syncQueue.take());
                      TimeUnit.SECONDS.sleep(3);
                      System.out.println(Thread.currentThread().getName() + "\t" + syncQueue.take());
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }, "BBB").start();
          }
      }
      
      运行结果:
      在这里插入图片描述
      • LinkedTransferQueue: 由链表结构组成的无界阻塞队列。
      • LinkedBlockingDeque: 由链表结构组成的双向阻塞队列。
        在这里插入图片描述
    • 抛出异常:当阻塞队列满时,再往队列里add插入元素会抛出IllegalStateException: Queue full;当阻塞队列空时,再往队列里remove移除元素会抛NoSuchElementException
      • add(): 添加元素,返回boolean
      • remove(): 移除队列头元素,返回元素,且删除元素
      • element(): 获取队列头元素,返回元素,但不删除元素
    • 特殊值:插入方法,成功true失败false;移除方法,成功返回出队列的元素,队列里面没有就返回null
      • offer(): 添加元素,返回boolean
      • poll(): 移除队列头元素,返回元素
      • peek(): 获取队列头元素,返回元素
    • 一直阻塞:当阻塞队列满时,生产者线程继续往队列里put元素,队列会一直阻塞生产线程知道put数据or响应中断退出;当阻塞队列满时,消费者线程试图从队列里take元素,队列会一直阻塞消费者线程直到队列可用。
    • 超时退出:当阻塞队列满时,队列会阻塞生产线程一定时间,超出后限时后生产者线程会退出
  2. synchronized和Lock有什么区别?
    • synchronized是一个关键字,Lock是一个类
    • synchronized不需要用户去手动释放锁,当synchronized代码执行完后系统会自动让线程释放对锁的占用;Lock则需要用户去手动释放锁若没有主动释放锁,就有可能导致出现死锁现象
    • synchronized不可中断,除非抛出异常或者正常运行完成;Lock可中断
    • synchronized非公平锁;Lock两者都可以,默认非公平锁,构造方法可以传入boolean值,true为公平锁,false为非公平锁
    • synchronized没有锁条件,Lock锁绑定多个条件condition用来实现分组唤醒需要唤醒的线程们,可以精确唤醒,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程。
  3. Condition?用于精确唤醒。是一个多线程间协调通信的工具类,使得某个或者某些线程一起等待某个条件(Condition),只有当该条件具备(signal或者signalAll方法被带调用)时,这些等待线程才会被唤醒,从而重新争夺锁。
    Condition是个接口,基本的方法就是await()和signal()方法;Condition依赖于Lock接口,生成一个Condition的基本代码是lock.newCondition()。调用Condition的await()和signal()方法,都必须在lock保护之内,就是说必须在lock.lock()和lock.unlock()之间才可以使用。
    • Condition中的await()对应Object的wait();
    • Condition中的signal()对应Object的notify();
    • Condition中的signalAll()对应Object的notifyAll();
      Demo: 多线程之间按顺序调用,实现A->B->C三个线程启动,要求如下:A打印5次,B打印10次,C打印15次,紧接着

      来10轮
class ShareResource {
    int number = 1;
    Lock lock = new ReentrantLock(false);
    Condition c1 = lock.newCondition();
    Condition c2 = lock.newCondition();
    Condition c3 = lock.newCondition();

    public void print5() {
        lock.lock();
        try {
            // 1.判断
            while (number != 1) {
                c1.await();
            }
            // 2.干活
            for (int i = 1; i <= 5; i++) {
                System.out.println(Thread.currentThread().getName() + "\t" + i);
            }
            // 3.通知唤醒
            number = 2;
            c2.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void print10() {
        lock.lock();
        try {
            while (number != 2) c2.await();
            for (int i = 1; i <= 10; i++) {
                System.out.println(Thread.currentThread().getName() + "\t" + i);
            }
            number = 3;
            c3.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void print15() {
        lock.lock();
        try {
            while (number != 3) c3.await();
            for (int i = 1; i <= 15; i++) {
                System.out.println(Thread.currentThread().getName() + "\t" + i);
            }
            number = 1;
            c1.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

public class ConditionDemo {
    public static void main(String[] args) {
        ShareResource shareResource = new ShareResource();

        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                shareResource.print5();
            }
        }, "A").start();
        
        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                shareResource.print10();
            }
        }, "B").start();

        new Thread(() -> {
            for (int i = 1; i <= 15; i++) {
                shareResource.print15();
            }
        }, "C").start();
    }
}
  1. Callable接口:JDK1.5新增的泛型接口,函数式接口(一个接口中只包含有一个方法)
    @FunctionalInterface
    public interface Callable<V> {
        /**
         * Computes a result, or throws an exception if unable to do so.
         *
         * @return computed result
         * @throws Exception if unable to compute a result
         */
        V call() throws Exception;
    }
    
    Callable: 返回结果并且可能抛出异常的任务。
    优点:①可以获得任务执行返回值;②通过与Future的结合,可以实现利用Future来跟踪异步计算的结果
  2. Runnable和Callable的区别
    • Callable规定的方法是call(),Runnable规定的方法是run()
    • Callable的任务执行后可返回值,而Runnable的任务是不能返回值的
    • call()方法可以抛出异常,run()方法不可以
    • 运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值