Object类与阻塞队列

Object类

介绍

  • Object类是Java所有类的根类,Java中的类都要直接或间接继承Object类,所以Object类中定义的方法是所有Java对象的通用行为

内容

  1. 首先,Object类中有一个空的的构造方法 public Object() {}。由于Java中如果子类没有显式地调用父类的构造方法,编译器会自动调用父类的构造方法,而Object是所有类的根类,如果没有构造方法,那么Java中的其他类在实例化时会找不到其Object类的构造方法而导致编译失败。
    不过如果一个类如果没有显式的定义构造方法,编译器会默认生成 一个构造方法,即使JDK的源码中现实的构造了这个方法,其效果也等价于"不编写构造方法,编译器自动构造一个构造方法"。
  2. public final native Class<?> getClass(); 该方法用于返回当前对象运行时类的class对象,class对象包括当前类的各种信息(类名、接口、方法、父类等)。
  3. public native int hashCode(); 该方法用于获取对象的哈希码,哈希码可以让哈希表以O(1)的时间复杂度进行插入、删除、查找操作。哈希表的存储逻辑是使用数组完成的,获得某个对象的哈希码后,可以通过哈希算法得到该对象的数组索引,用数组的索引访问可以得到桶,而由于桶内的元素通常是常数,在桶内(链表等方式存储)进行增删查的操作的时间复杂度也是O(1),所以哈希码可以使Java集合框架高效运行
  4. public boolean equals(Object obj) { return (this == obj); } 该方法通过比较两个对象的引用地址来判断两个对象是否相等。如果需要判断两个对象的逻辑是否相同,而不是简单的判断引用地址是否相同的话,则需要重写equals方法,重写equals方法的同时也需要重写hashCode方法 ,因为相同对象的哈希码必须相同
  5. protected native Object clone() throws CloneNotSupportedException;该方法用于克隆一个对象的副本。该副本需要满足:副本与原始对象应是不同对象;副本与原始对象对应的类应相同;副本与原始对象在逻辑上相等(需重写equals方法),但不强制(因为clone方法默认执行浅拷贝,只复制当前字段值,如果需要深拷贝,直接重写clone方法即可)。
  6. public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }该方法用于返回对象的"文本表示",其默认返回格式为"类名+@+哈希码的十六进制无符号表示",一般对于自定义的类,我们是需要进行重写toString方法以得到更加可读的文本信息。
  7. 线程同步的相关方法: notify(),notifyAll(),wait() 这三个方法都是用于多线程间的协作,必须由持有线程监听器锁的线程调用,否则会抛出异常。对象监听器的工作流程:
  • 某个对象obj会有一个关联的monitor(对象监听器),这个monitor会维护两个队列:入口集(Entry Set)、等待集(Wait Set)。入口集用于存放所有正在等待获取monitor锁的线程,等待集用于存放调用了obj.wait()方法后,释放锁并等待的线程。初始状态monitor并未被任何线程持有(锁空闲)
  • 当线程t1进入synchronized(obj){}时,该线程会尝试持有obj的monitor,此时obj的monitor并未被持有,因此t1线程成功持有obj的monitor,并开始执行synchronized代码块中的代码。
  • 若此时有一个线程t2尝试进入synchronized(obj){}时,由于obj的monitor已经被线程t1所占用,t2无法获取monitor并会被阻塞,此时的t2将会进入入口集并等待。
  • 此时如果t1在执行synchronized(obj){}代码块时执行了wait()方法,t1线程会释放锁,并进入等待集进行等待。此时obj的monitor便会被释放,处于空闲状态,位于入口集的线程(如t2)会竞争该monitor
  • 当t2持有锁之后,开始执行代码块中的内容,若此时执行了notify()方法,等待集中的线程会被随机选择一个,将它转移到入口集。
  • t2执行完毕代码或执行wait()后,它会释放锁,此时位于入口集的线程会竞争锁,谁拿到了monitor谁就可以执行代码块中的内容。假如是刚刚的t1拿到了锁,它就会从wait()的调用处继续执行代码,因此,wait()经常会放在while循环中,直到条件满足后才让它继续执行代码。

阻塞队列的实现

思路逻辑

用好wait()notifyAll()方法,让队列满(空)的时候,无法进行入队(出队)操作即可

代码实现

java 复制代码
package com.nwu.by0321_SimpleBlockingQueue;

import java.util.LinkedList;

public class SimpleBlockingQueue <T> {
    private LinkedList<T> list ;    //用链表来实现队列
    int capacity;
    public SimpleBlockingQueue(int capacity) {  //创建构造方法,判断大小是否合规
        if (capacity <= 0) {
            throw new IllegalArgumentException();
        }
        this.capacity = capacity;
        list=new LinkedList<>();
    }

    public synchronized int size(){
        return list.size();
    }

    public synchronized void put(T t) throws InterruptedException{  //入队方法
        //若队列满,则等待
        while(list.size()==capacity){
            wait();
        }
        //未满则直接添加元素
        list.add(t);
        notifyAll();
    }

    public synchronized T take() throws InterruptedException{   //出队
        //如果为空则等待
        while(list.isEmpty()){
            wait();
        }
        T t=list.remove();
        notifyAll();
        return t  ;//删除并返回第一个值
    }
}
class Main{
    public static void main(String[] args) {
        SimpleBlockingQueue<String> bq=new SimpleBlockingQueue<>(5);
        Thread t1= new Thread(){    //生产线程
            @Override
            public void run() {
                for (int i = 1; i <= 21; i++) {
                    if(i!=21){
                        try {
                            sleep(500);
                            bq.put("Task"+i);//添加10个任务
                            System.out.println("正在生产任务----------"+"Task"+i);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }else{
                        try {
                            bq.put(" ");
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }

                }
            }
        };
        t1.start();
        Thread t2= new Thread(){    //加工线程
            @Override
            public void run() {
                while(true){
                    try {
                        sleep(1000);
                        String str=bq.take();
                        System.out.println(str+"已完成加工");
                        if(str.equals(" ")){
                            break;
                        }
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        };
        t2.start();
        Thread t3= new Thread(){    //监听线程
            @Override
            public void run() {
                while (true) {
                    try {
                        sleep(500);
                        System.out.println("当前还剩"+bq.size()+"个任务未加工完成");
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        };
        t3.start();
    }
}

运行截图

相关推荐
大福猫2 小时前
#一个33岁新手小白在黑马学习程序员的第四天-1
java
Java基基2 小时前
Idea 插件推荐可直接修改jar包内文件的IDEA插件,无需解压
java·ide·intellij-idea
刘大猫.2 小时前
java工具:《返回字符串非零的最后一个层级》
java·字符串·java字符串·返回非零层级·解析字符串
左左右右左右摇晃2 小时前
Java笔记 —— 值传递与“引用传递”
java·开发语言·笔记
2301_792674862 小时前
java学习day22
java
于慨2 小时前
spring boot
java·数据库·spring boot
always_TT2 小时前
static关键字初探
java·开发语言
降临-max2 小时前
IDEA常用git操作
java·github·intellij-idea
爱丽_2 小时前
G1 深入:Region、Remembered Set、三色标记与“可预测停顿”
java·数据库·算法