Java Thread多线程开发中Object类详细讲解

目录
  • 方法概览
    • Thread
  • wait  notify notifyAll方法详解
    • 作用
      • 阻塞阶段
      • 唤醒阶段
      • 遇到中断
    • 代码展示
    • 特点
    • 通过wait notify方法实现生产者和消费者
  • sleep方法详解
    • sleep不会释放锁
    • sleep响应中断
    • 总结
  • join方法详解
    • 代码展示
  • yield方法

方法概览

Thread

wait  notify notifyAll方法详解

作用

阻塞阶段

使用了wait方法之后,线程就会进入阻塞阶段,只有发生以下四种情况中的其中一个,线程才会被唤醒

  • 另一个线程调用了这个线程的notify方法,刚好唤醒的是本线程
  • 另一个线程调用了这个对象的notifyAll方法
  • 过了wait规定的超时时间
  • 线程调用了interrupt

唤醒阶段

notify会唤醒单个处于阻塞状态的线程,唤醒的线程是随机的

notify和wait都需要写在synchronized代码块里,不然会抛出异常

notifyAll会唤醒所有等待的线程

遇到中断

执行wait方法之后,被中断,会抛出InterruptedException这个异常

代码展示

  • 展示wait和notify的基本用法
  • 该代码执行wait方法之后会释放锁,然后thread2执行notify方法
  • notify方法执行完毕之后,并没有立即释放锁,而是接着执行之后的代码,也就是打印“Thread2调用notify”这句话
  • thread2执行完毕之后,会进行释放锁,thread1才会继续执行
  • 在此期间,thread1虽然被唤醒,但是一直在等待thread2同步代码块里面的代码执行完毕
public class Wait {
    public static void main(String[] args) throws InterruptedException {
        Thread1 thread1 = new Thread1();
        Thread2 thread2 = new Thread2();
        thread1.start();
        Thread.sleep(200);
        thread2.start();
    }
    public static Object object = new Object();
    static class Thread1 extends Thread {
        @Override
        public void run() {
            synchronized (object) {
                System.out.println("Thread1执行");
                try {
                    object.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread1获取锁");
            }
        }
    }
    static class Thread2 extends Thread {
        @Override
        public void run() {
            synchronized (object) {
                object.notify();
                System.out.println("Thread2调用notify");
            }
        }
    }
}
/*
Thread1执行
Thread2调用notify
Thread1获取锁
* */
  • notify和notifyAll的展示
  • 第一个输出:threadc调用notifyAll
  • 第二个输出:threadc调用notify
  • 调用notify的时候,程序并没有结束,threadb陷入等待
public class notifyOrAll implements Runnable{
    private static final Object a = new Object();
    public static void main(String[] args) throws InterruptedException {
        Runnable r = new notifyOrAll();
        Thread threada = new Thread(r);
        Thread threadb = new Thread(r);
        Thread threadc = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (a) {
//                    a.notifyAll();
                    a.notify();
                    System.out.println(Thread.currentThread().getName() + "notify");
                }
            }
        });
        threada.start();
        Thread.sleep(200);
        threadb.start();
        Thread.sleep(200);
        threadc.start();
    }
    @Override
    public void run() {
        synchronized (a) {
            System.out.println(Thread.currentThread().getName() + "得到锁");
            try {
                System.out.println(Thread.currentThread().getName() + "wait");
                a.wait();
                System.out.println(Thread.currentThread().getName() + "wait结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
/*
Thread-0得到锁
Thread-0wait
Thread-1得到锁
Thread-1wait
Thread-2notifyAll
Thread-1wait结束
Thread-0wait结束
* */
/*
Thread-0得到锁
Thread-0wait
Thread-1得到锁
Thread-1wait
Thread-2notify
Thread-0wait结束
* */
  • 只释放当前monitor
  • 证明wait只释放当前的那把锁
public class OwnMonitor {
    private static volatile Object a = new Object();
    private static volatile Object b = new Object();
    public static void main(String[] args) throws InterruptedException {
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (a) {
                    System.out.println("threadA得到a");
                    synchronized (b) {
                        System.out.println("threadA得到锁b");

                        try {
                            System.out.println("threadA释放a");
                            a.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        });
        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (a) {
                    System.out.println("threadB得到a");
                    System.out.println("threadB要获取b");
                    synchronized (b) {
                        System.out.println("threadB得到b");
                    }
                }
            }
        });
        threadA.start();
        Thread.sleep(1000);
        threadB.start();
    }
}
/*
threadA得到a
threadA得到锁b
threadA释放a
threadB得到a
threadB要获取b
* */

特点

  • 执行这些方法必须先获取锁
  • notify只能换取一个,而且是随机的
  • 都属于Object。任何对象都可以调用
  • 都是native final修饰的

当线程从wait状态刚被唤醒时,通常不能直接得到锁,那就会从waiting状态转换到blocked状态,抢到锁之后状态转变为runnable

如果发生异常,则直接跳到Terminated状态

通过wait notify方法实现生产者和消费者

  • 将storge当作生产者和消费者进行工作的仓库
  • 如果storge中没有数据,生产者就开始wait
  • 如果storge中数据满了,消费者就开始wait
  • 生产者和消费者每进行一次生产和消费,就执行notify
public class ProducerConsumer {
    public static void main(String[] args) {
        Storge storge = new Storge();
        Producer producer = new Producer(storge);
        Consumer consumer = new Consumer(storge);
        new Thread(producer).start();
        new Thread(consumer).start();
    }
}
class Producer implements Runnable {
    private Storge storge;
    public Producer(Storge storge) {
        this.storge = storge;
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            storge.put();
        }
    }
}
class Consumer implements Runnable {
    private Storge storge;
    public Consumer(Storge storge) {
        this.storge = storge;
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            storge.take();
        }
    }
}
class Storge {
    private int maxSize;
    private LinkedList<Date> storge;
    public Storge() {
        maxSize = 10;
        storge = new LinkedList<>();
    }
    public synchronized void put() {
        while (storge.size() == maxSize) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        storge.add(new Date());
        System.out.println("已经有了" + storge.size());
        notify();
    }
    public synchronized void take() {
        while (storge.size() == 0) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("拿到了" + storge.poll() + "还剩" + storge.size());
        notify();
    }
}

sleep方法详解

作用:让线程在预期的时间执行,其他时间不占用CPU资源

特点:和wait不一样,sleep不释放锁

sleep不会释放锁

证明sleep不会释放 synchronized锁

public class SleepSyn implements Runnable{
    public static void main(String[] args) {
        SleepSyn sleepSyn = new SleepSyn();
        new Thread(sleepSyn).start();
        new Thread(sleepSyn).start();
    }
    @Override
    public void run() {
        syn();
    }
    private synchronized void syn() {
        System.out.println(Thread.currentThread().getName() + "获取锁");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "释放锁");
    }
}
/*
* Thread-0获取锁
Thread-0释放锁
Thread-1获取锁
Thread-1释放锁
* */

证明sleep不释放Lock锁

public class sleepLock implements Runnable{
    private static final Lock LOCK = new ReentrantLock();
    @Override
    public void run() {
        LOCK.lock();
        System.out.println(Thread.currentThread().getName() + "获取锁");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            LOCK.unlock();
        }
        System.out.println(Thread.currentThread().getName() + "释放锁");
    }
    public static void main(String[] args) {
        sleepLock sleepLock = new sleepLock();
        new Thread(sleepLock).start();
        new Thread(sleepLock).start();
    }
}
/*
* Thread-0获取锁
Thread-0释放锁
Thread-1获取锁
Thread-1释放锁
* */

sleep响应中断

  • 抛出InterruptedException
  • 会清除中断状态
  • 中断之后,抛出异常继续执行
public class sleepInterrupted implements Runnable{
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new sleepInterrupted());
        thread.start();
        Thread.sleep(2000);
        thread.interrupt();
    }
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(new Date());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                System.out.println("中断");
                e.printStackTrace();
            }
        }
    }
}
/*
* Fri Jan 27 21:11:57 CST 2023
Fri Jan 27 21:11:58 CST 2023
中断
Fri Jan 27 21:11:59 CST 2023
java.lang.InterruptedException: sleep interrupted
   at java.lang.Thread.sleep(Native Method)
   at java.lang.Thread.sleep(Thread.java:340)
   at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
   at com.jx.JavaTest.ThreadObjectMethod.sleepInterrupted.run(sleepInterrupted.java:21)
   at java.lang.Thread.run(Thread.java:748)
Fri Jan 27 21:12:00 CST 2023
Fri Jan 27 21:12:01 CST 2023
Fri Jan 27 21:12:02 CST 2023
Fri Jan 27 21:12:03 CST 2023
Fri Jan 27 21:12:04 CST 2023
Fri Jan 27 21:12:05 CST 2023
Fri Jan 27 21:12:06 CST 2023
Process finished with exit code 0
* */

总结

sleep方法可以让线程进入waiting状态,不占用CPU资源,但是不释放锁,规定时间之后再运行

休眠期间如果被打断,会抛出异常并清除中断状态

join方法详解

新线程加入,主线程等子线程执行完毕

代码展示

  • 前一个结果是使用join
  • 后一个结果是没使用join
  • 可知使用join之后,主线程会等join的线程执行完毕再继续执行
public class join {
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "执行完毕");
            }
        });
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "执行完毕");
            }
        });
        thread1.start();
        thread2.start();
        System.out.println("开始等待子线程运行");
//        thread1.join();
//        thread2.join();
        System.out.println("所有线程执行完毕");
    }
}
/*
* 开始等待子线程运行
Thread-0执行完毕
Thread-1执行完毕
所有线程执行完毕
* */
/*
* 开始等待子线程运行
所有线程执行完毕
Thread-1执行完毕
Thread-0执行完毕
* */
  • 遇到中断
  • 第一个的运行结果是主线程没中断的打印结果
  • 第二个的运行结果是join期间进行中断的打印结果,可知在打印了“子线程运行完毕”之后,依然打印了“启动”两个字,可知会造成运行混乱
  • 可以在捕获异常的代码块中,将join的线程也中断,可以解决上面的问题
public class joinInterrupt {
    public static void main(String[] args) {
        Thread main1 = Thread.currentThread();
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    main1.interrupt();
                    Thread.sleep(2000);
                    System.out.println("启动");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread1.start();
        System.out.println("join");
        try {
            thread1.join();
        } catch (InterruptedException e) {
            System.out.println(Thread.currentThread().getName() + "中断");
            // thread1.interrupt();
            e.printStackTrace();
        }
        System.out.println("子线程运行完毕");
    }
}
/*
* join
启动
子线程运行完毕
* */
/*
* join
main中断
子线程运行完毕
java.lang.InterruptedException
   at java.lang.Object.wait(Native Method)
   at java.lang.Thread.join(Thread.java:1252)
   at java.lang.Thread.join(Thread.java:1326)
   at com.jx.JavaTest.ThreadObjectMethod.joinInterrupt.main(joinInterrupt.java:23)
启动
Process finished with exit code 0
* */
/*
* join
main中断
子线程运行完毕
java.lang.InterruptedException: sleep interrupted
   at java.lang.Thread.sleep(Native Method)
   at com.jx.JavaTest.ThreadObjectMethod.joinInterrupt$1.run(joinInterrupt.java:13)
   at java.lang.Thread.run(Thread.java:748)
java.lang.InterruptedException
   at java.lang.Object.wait(Native Method)
   at java.lang.Thread.join(Thread.java:1252)
   at java.lang.Thread.join(Thread.java:1326)
   at com.jx.JavaTest.ThreadObjectMethod.joinInterrupt.main(joinInterrupt.java:23)
Process finished with exit code 0
* */

join期间,线程处于WAITING状态

public class joinStates {
    public static void main(String[] args) throws InterruptedException {
        Thread main1 = Thread.currentThread();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                    System.out.println(main1.getState());
                    System.out.println("子线程运行结束");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        System.out.println("join");
        thread.join();
        System.out.println("运行完毕");
    }
}
/*
* join
WAITING
子线程运行结束
运行完毕
* */

yield方法

用来释放CPU时间片,但是不一定能达到预期的效果,因为有时CPU资源不紧张,无需yield

和sleep的区别是:sleep期间不会被再次调度但是yield会立刻处于竞争状态,还会随时再次被调度

到此这篇关于Java Thread多线程开发中Object类详细讲解的文章就介绍到这了,更多相关Java Object类内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java将Object转换为数组的代码

    今天在使用一个别人写的工具类,这个工具类,主要是判空操作,包括集合.数组.Map等对象是否为空的操作. 下面展示了一部分代码: public static boolean isEmpty(Object object) { if(object == null){ return true; } //数组判空 if (object.getClass().isArray()) { Object[] obj = (Object[])object; return obj.length == 0; } } 在

  • 一文带你搞懂Java中Object类和抽象类

    目录 一.抽象类是什么 二.初始抽象类 2.1 基本语法 2.2 继承抽象类 三.抽象类总结 四.Object类 4.1 初始Object 4.2 toString 4.3 equals 4.4 hashcode 一.抽象类是什么 在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类. 由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用.也是因为这个原因,通常在设计阶段决定要

  • 一文搞懂Java顶层类之Object类的使用

    目录 概述 toString方法 方法摘要 覆盖重写 equals方法 方法摘要 默认地址比较 对象内容比较 Objects类 概述 java.lang.Object类是Java语言中的根类,即所有类的父类.它中描述的所有方法子类都可以使用.在对象实例化的时候,最终找的父类就是Object. 如果一个类没有特别指定父类,那么默认则继承自Object类.例如: public class MyClass /*extends Object*/ { // ... } 根据JDK源代码及Object类的A

  • 一文带你了解Java中的Object类及类中方法

    目录 1. Object类介绍 2. 重写toString方法打印对象 3. 对象比较equals方法 4. hashCode方法 1. Object类介绍 Object是Java默认提供的一个类.Java里面除了Object类,所有的类都是存在继承关系的.默认会继承Object父 类.即所有类的对象都可以使用Object的引用进行接收. 范例:使用Object接收所有类的对象 class Person{} class Student{} public class Test { public s

  • 深入了解Java Object类的使用

    目录 1.equals方法 ==运算符 equals 2.hashCode 3.toString 4.finalize 1.equals方法 ==运算符 比较运算符,即可以判断基本类型又可以判断引用类型 如果判断基本类型,则判断值是否相等 如果判断引用类型,则判断地址是否相等,即判断是否为同一个对象 equals 是object类的一个方法,只能判断引用类型 object - equals源码: public boolean equals(Object obj) { return (this =

  • Java Thread多线程开发中Object类详细讲解

    目录 方法概览 Thread wait  notify notifyAll方法详解 作用 阻塞阶段 唤醒阶段 遇到中断 代码展示 特点 通过wait notify方法实现生产者和消费者 sleep方法详解 sleep不会释放锁 sleep响应中断 总结 join方法详解 代码展示 yield方法 方法概览 Thread wait  notify notifyAll方法详解 作用 阻塞阶段 使用了wait方法之后,线程就会进入阻塞阶段,只有发生以下四种情况中的其中一个,线程才会被唤醒 另一个线程调

  • java中dart类详细讲解

    dart 是一个面向对象的语言;面向对象有 继承 封装 多态 dart的所有东西都是对象,所有的对象都是继承与object类 一个类通常是由属性和方法组成的 在dart中如果你要自定义一个类的话,将这个类放在main函数外面 类名使用大驼峰方法名使用小驼峰 1.定义这个类的属性和方法 //定义一个类的属性和方法 class Person { String name = '张三'; int age = 19; void getInfo() { // print('我叫$name,今年$age');

  • 实例解析iOS应用多线程开发中NSthread类的用法

    一.NSthread的初始化 1.动态方法 复制代码 代码如下: - (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument;  // 初始化线程  NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  // 设置线程的优先级(0.0 - 1.0,1.0最高级)  thre

  • java中Object类4种方法详细介绍

    目录 Object(四大方法): hashCode()方法: equals()方法: getClass()方法: toString()方法: 总结 Object(四大方法): 文章干货满满,耐性看完~~何为Object?首先先来看看官方对Object的介绍:在这里附上Java官方的查阅工具:https://docs.oracle.com/en/java/javase/17/docs/api/index.html 由官方介绍可见,object属于Java.lang包内的一个类,而且提供了很多种方法

  • 详谈Java中Object类中的方法以及finalize函数作用

    Object是所有类的父类,任何类都默认继承Object. 一.Object类中的方法 1.clone方法 保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常. 主要是JAVA里除了8种基本类型传参数是值传递,其他的类对象传参数都是引用传递,我们有时候不希望在方法里讲参数改变,这是就需要在类中复写clone方法. 2.getClass方法 final方法,获得运行时类型. 3.toString方法 该方法

  • java开发中嵌套类的详解及实例

     java开发中嵌套类的详解 在java语言规范里面,嵌套类(Nested Classes)定义是: A nested class is any class whose declaration occurs within the body of another class or interface. A top level class is a class that is not a nested class. 说的简单一点,就是定义在类里面的类.一般把定义内部类的外围类成为包装类(enclos

  • Java中ArrayList类详细介绍

    Java中ArrayList类详细介绍 ArrayList是一个可变长度数组,它实现了List接口,因此它也可以包含重复元素和Null元素,也可以任意的访问和修改元素,随着向 ArrayList 中不断添加元素,其容量也自动增长.不过ArrayList是非同步(同步的意思是如果多个线程同时访问一个实例,任何一个线程对实例做了修改之后,其他线程所访问到的实例应该是修改过的最新的实例)的, 我们经常使用List list = Collections.synchronizedList(new Arra

  • java中object类实例分析

    问:什么是Object类? 答:Object类存储在java.lang包中,是所有java类(Object类除外)的终极父类.当然,数组也继承了Object类.然而,接口是不继承Object类的,Object类不作为接口的父类. 下面,我们就通过实例,对object进行分析 public class ObjectStu { /*Object类:java里所有类的父类,顶层的类 *equals:判断两个对象是否"相等"; *hashcode:返回一个对象的哈希码值,是一个整数 *因为之后

  • Java中Object类常用的12个方法(小结)

    目录 前言 1. getClass 方法 2. hashCode 方法 3. equals 方法 4. clone 方法 5. toString 方法 6. notify 方法 7. notifyAll 方法 8. wait(long timeout) 方法 9. wait(long timeout, int nanos) 方法 10. wait 方法 11. finalize 方法 前言 Java 中的 Object 方法在面试中是一个非常高频的点,毕竟 Object 是所有类的"老祖宗&qu

随机推荐