java.lang.Object 的 wait 和 notify方法,及关键字 synchronized的作用

1. synchronized的作用

synchronized类似于win32中的临界区,临界区的作用:对于共享的全局变量,在多个线程并发的情况下,对这样的全局变量的读写就会发生读写的冲突,

使得全局变量的读写,能够以原子的方式被执行,而不是一个线程要读取全局数据时候,由于线程调度,而另一个线程则此时被唤醒,改变了这个全局变量的值,

这样使得读取的线程获得的数据不稳定,所以对于全局变量的读写的代码,我们要使用临界区使得这些代码原子化,此时只要在临界区中的代码,就会以原子方式执行,

而不会由于线程调度被中断,也就保证了全局共享资源的互斥访问。例如:

CRITICAL_SECTION CriticalSection;   // 临界区对象

1 DWORD WINAPI WriteThreadProc( LPVOID lpParameter )
2 {
3     // 进入临界区
4     EnterCriticalSection(&CriticalSection);
5     // 写资源
6     g_data = 123;
7     // 离开临界区
8     LeaveCriticalSection(&CriticalSection);
9 }  
DWORD WINAPI ReadThreadProc( LPVOID lpParameter )
{
    // 进入临界区
    EnterCriticalSection(&CriticalSection);
    // 读资源
    printf(g_data);
    // 离开临界区
    LeaveCriticalSection(&CriticalSection);
}  

上面的例子中的在临界区中,进行数据读写,就不会发生共享资源冲突。类似的,在java中使用 synchronized 关键字来实现临界区代码块。

关于的synchronized 使用方法,参考:Java synchronized详解

2. java.lang.notify 方法

每一个对象都有一个所谓的 object‘s monitor(对象监视器)。假设其为:obj.monitor。能够获得obj对象的引用的线程都可以通过 obj.wait() 方法在这个对象监视器(obj.monitor)上注册一个监听。这样所有调用 obj.wait的线程都将添加到,对象的类似等待队列中。

JDK文档翻译:

唤醒在此对象监视器上等待的单个线程。如果有多个线程都在此对象上等待(也就是线程中执行了 obj.wait),则会选择唤醒其中一个线程。选择是任意性(随机的)的,并在对实现做出决定时发生。线程通过调用其中一个 wait 方法,在对象的监视器上等待

直到当前线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争;例如,唤醒的线程在作为锁定此对象的下一个线程方面没有可靠的特权或劣势。

此方法只应由作为此对象监视器的所有者的线程来调用。通过以下三种方法之一,线程可以成为此对象监视器(obj.monitor)的所有者:

  • 通过执行此对象的同步实例方法。(也就是方法签名上有 synchronized 关键字的实例方法,也就是执行 obj.instanceMethod ,并且这个方法有synchronized 修饰)
  • 通过执行在此对象上进行同步的 synchronized 语句的正文。(synchronized代码块, 也就是 synchronized(obj){obj.wait();} 这样这个代码块中就具有了 obj.monitor,就可以调用 obj.wait 了)
  • 对于 Class 类型的对象,可以通过执行该类的同步静态方法。(也就是方法签名上有 synchronized 关键字的实例方法,也即类级方法,也就是obj.staticMehtod,并且这个方法的签名有synchronized 关键词修饰)

一次只能有一个线程拥有对象的监视器。

在上面三种情况下,线程就拥有了对象监视器(obj.monitor)则就可以在其中调用 obj.notify 方法了。

线程可以成为此对象监视器(obj.monitor)的所有者:的第一种情况 同步对象就是 this 当前的实例对象。所以在这个实例方法中就可以这样调用:this.notify();

第三种情况下,其实也就是同步对象就是 ThreadTest.class.wait(); 也就是在类对象上调用 notify 方法。

第二种情况下,由于我们可以手动的指定指定我们要获得的监视器的对象,此时就不仅仅是 this 和 ClassName.class 这两个对象了,可以是其他的任何对象,例如 waitObj 这个对象对所有线程都可见,专门用来协调多线程并发的情况。

时间: 2024-08-25 04:06:20

java.lang.Object 的 wait 和 notify方法,及关键字 synchronized的作用的相关文章

java 数组的 toString 方法和 equals 方法以及 java.lang.Object 对象的 toString 方法和 equals 方法

1 public class Test { 2 public static void main(String[] args) { 3 int[] a = {1, 2, 4, 6}; 4 int[] b = a; 5 int[] c = {1, 2, 4, 6}; 6 7 //下面这个方法打印的是a数组的引用地址 8 System.out.println(a.toString()); 9 //下面这个方法比较的是两个数组的引用是否相等 10 System.out.println("a.equals

java.lang.Object底层代码分析-jdk1.8

首先先来说明两件事情 1.后面的一些博客都会对jdk底层的方法进行一些分析,因为我个人开发了2年多,发现有很多事情还不是清楚,当我今天再好好底层源码的时候还是有不少的收获,所以和大家分    享一下,我只要参考一下相关文档 jdk1.8api:https://docs.oracle.com/javase/8/docs/api/index.html 代码下载地址:https://gitee.com/luanmihun/java-jdk-study 2.为什么要分析jdk1.8的版本,只是一些个人的

深入研究java.lang.Object类

一.概述:       Object类是所有Java类的祖先.每个类都使用 Object 作为超类.所有对象(包括数组)都实现这个类的方法.在不明确给出超类的情况下,Java会自动把Object作为要定义类的超类.      可以使用类型为Object的变量指向任意类型的对象.      Object类有一个默认构造方法pubilc Object(),在构造子类实例时,都会先调用这个默认构造方法.      Object类的变量只能用作各种值的通用持有者.要对他们进行任何专门的操作,都需要知道它

java.lang.Object.hashCode()的返回值到底是不是对象内存地址?

刚学Java的时候我也有过这种怀疑,但一直没有验证:最近在OSCHINA上看到有人在回答问题时也这么说,于是萌生了一探究竟的想法--java.lang.Object.hashCode()的返回值到底是不是对象内存地址? (顺带回顾一下JNI) hashCode契约 说到这个问题,大家的第一反应一定和我一样--去查Object.hashCode的源码,但翻开源码,看到的却是这样的(Oracle JDK 8): /** * Returns a hash code value for the obje

研究java.lang.Object类

一.概述:        Object类是所有Java类的祖先.每个类都使用 Object 作为超类.所有对象(包括数组)都实现这个类的方法. 在不明确给出超类的情况下,Java会自动把Object作为要定义类的超类.       可以使用类型为Object的变量指向任意类型的对象.       Object类有一个默认构造方法pubilc Object(),在构造子类实例时,都会先调用这个默认构造方法.       Object类的变量只能用作各种值的通用持有者.要对他们进行任何专门的操作,都

jdk源码每日一读 (一) java.lang.Object

jdk源码每日一读 (一) java.lang.Object 1. 类说明 Object是java继承体系的根,是每一个类的基类,所有的类都实现了Object类的所有方法. 2.重要方法 public final native Class<?> getClass() public native int hashCode(); public boolean equals(Object obj); protected native Object clone() throws CloneNotSup

Java总结篇系列:java.lang.Object

从本篇开始,将对Java中各知识点进行一次具体总结,以便对以往的Java知识进行一次回顾,同时在总结的过程中加深对Java的理解. Java作为一个庞大的知识体系,涉及到的知识点繁多,本文将从Java中最基本的类java.lang.Object开始谈起. Object类是Java中其他所有类的祖先,没有Object类Java面向对象无从谈起.作为其他所有类的基类,Object具有哪些属性和行为, 是Java语言设计背后的思维体现. Object类位于java.lang包中,java.lang包包

java.lang.Object 之 clone() 使用

Java的所有类都默认继承 java.lang.Object 类,在 java.lang.Object 类中有一个方法 clone().JDK API的说明文档解释这个方法将返回Object对象的一个拷贝.要说明的有两点:一是拷贝对象返回的是一个新对象,而不是一个引用.二是拷贝对象与用 new操作符返回的新对象的区别就是这个拷贝已经包含了一些原来对象的信息,而不是对象的初始信息.对于Java中使用 clone() 方法有几点需要注意 1:被clone的类必须实现 Cloneable 接口,Clo

java.lang.Object

java.lang包在使用的时候无需显示导入,编译时由编译器自动导入. Object类是类层次结构的根,Java中所有的类从根本上都继承自这个类. Object类是Java中唯一没有父类的类. 其他所有的类,包括标准容器类,比如数组,都继承了Object类中的方法. Object类中的方法 构造方法:public Object() 文档中的类概览: Java中的每个类都具有定义在Object类中的这些方法. protected Object clone() Creates and returns