文章目录
2.0 JAVA同步锁 synchronized(this)、synchronized(class)与synchronized(Object)的区别
2.7 Object类方法之notify和notifyAll方法
2.10 propertyIsEnumerable(prop)
前言
本文主要介绍object以及object的相关方法
1. object介绍
1.1 简单介绍
Object对象是JavaScript中的顶级对象,它是所有其他对象的基类。它具有一些通用的属性和方法,可以被所有其他对象继承和使用。
Object类是Java中其他所有类的祖先,没有Object类Java面向对象无从谈起。作为其他所有类的基类,Object具有哪些属性和行为,是Java语言设计背后的思维体现。
1.2 object的相关方法
Object类位于java.lang包中,java.lang包包含着Java最基础和核心的类,在编译时会自动导入。Object类没有定义属性,一共有13个方法,具体的类定义结构如下图:
2. object相关方法的介绍
Object类是所有类的超类,所有类都默认继承Object 数组也会继承Object类中的方法
2.0 JAVA同步锁 synchronized(this)、synchronized(class)与synchronized(Object)的区别
当一个线程访问Synchronized类的一个synchronized (this)同步代码块时,其它线程对同一个Synchronized类中其它的synchronized ()同步方法的访问将是堵塞;访问synchronized (Synchronized.class)同步代码块时, static synchronized同步方法的访问将是阻塞,这说明synchronized (this)和synchronized ()同步方法、synchronized (Synchronized.class)同步代码块和 static synchronized同步方法使用的对象监视器是一个。
多个线程调用同一个对象中的不同名称的synchronized同步方法或synchronized(this)同步代码块时,是同步的。
synchronized同步方法和synchronized(this)同步代码块是相互竞争关系
对其它的synchronized同步方法或synchronized(this)同步代码块调用是堵塞状态; 同一时间只有一个线程执行synchronized同步方法或synchronized(this)同步代码块中的代码。
synchronized应用在static方法上,那是对当前对应的.Class进行持锁,与同步synchronized(.class)代码块作用一样。
同步synchronized(*.class)
代码块的作用其实和synchronized static
方法作用一样。 Class锁对类的所有对象实例起作用。
此处参考博客:
JAVA同步锁 synchronized(this)、synchronized(class)与synchronized(Object)的区别_鳄鱼儿的博客-CSDN博客
2.1 Object之wait
Object的wait方法被设计为子类不可重写(Override)此方法采用native修饰,是JVM提供的方法
public final native void wait(long timeout) throws InterruptedException;
wait:
-
当调用wait时,当前线程持有对象的监视器(锁)
-
当前线程获取到对象锁后,调用此方法将导致当前的线程释放当前的对象锁并且让出cpu资源
-
当前线程进入阻塞状态(等待),直到其他线程调用此对象的notify()方法或notifyAll()方法唤醒或超过指定的时间量
注意事项: 当前线程不是锁的持有者(未被监视) 调用该方法抛出一个IllegalMonitorStateException异常 例:
package com.java265;
public class TestClass {
public static void main(String[] args) throws InterruptedException {
TestClass obj = new TestClass();
obj.wait(10);
}
}
此时抛出异常
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
注意事项: 调用wait方法只能在同步代码块或同步方法中 正确的写法
synchronized (obj) {
while (<condition does not hold>)
obj.wait(timeout);
... // Perform action appropriate to condition
}
2.1.1 另外两种wait方法
Object中除了native的wait方法,还有另外两个wait方法,他们的内部实现都是基于native的wait方法的,只是阻塞时间上的差异。
public final void wait() throws InterruptedException {
wait(0);
}
public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos > 0) {
timeout++;
}
wait(timeout);
}
注意事项:
-
当设置的时间为0时,线程只会等待其他线程通过notify()方法或notifyAll()方法唤醒,否则一直阻塞下去
-
当设置的时间大于0,如果过了等待时间,此时对象锁被其他线程持有,当前线程也会继续等待
当一个线程被wait时,如果需继续执行,必须满足以下任一条件
-
1.由其他线程notify或notifyAll,且当前线程被通知,和其他线程进行锁竞争,成功获取锁
-
2.没有被notify或notifyAll通知到,但过了wait超时时间和其他线程进行锁竞争,成功获取锁Object中notify、notifyAll
2.1.2 Object中notify,notifyAll
注意事项: Object中notify,notifyAll是不可被子类覆盖,并且两个方法都是native
public final native void notify();
public final native void notifyAll();
-
调用notify方法将唤醒在此对象监视器上等待的单个线程
-
如果所有线程都在此对象上等待,则会选择唤醒其中一个线程
-
此种选择是任意性的。
-
线程通过调用其中一个wait方法,在对象的监视器上等待,
-
直到当前的线程放弃此对象上的锁定,才能继续执行被唤醒的线程
-
被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争
-
所以notify会随机选择一个在该对象上调用wait方法的线程,解除其阻塞状态,该方法只能在同步方法或同步块内部调用,
-
如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。
-
notifyAll会解除所有那些在该对象上调用wait方法的线程的阻塞状态
-
该方法只能在同步方法或同步块内部调用
-
如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。
例如:
import java.util.LinkedList;
import java.util.List;
public class ProducerStorageConsumer {
/** 仓库 */
static class Storage {
/** 仓库最大容量 */
private int maxSize;
/** 仓库容器 */
private List<Object> storage;
public Storage(int maxSize) {
super();
this.maxSize = maxSize;
this.storage = new LinkedList<Object>();
}
/**
* 向仓库中添加产品
* @param object
*/
public synchronized void add(Object object) {
// 仓库容量满了,生产者暂停生产
while (storage.size() == maxSize) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 生产者添加产品到仓库,通知所有消费者获取产品
storage.add(object);
System.out.printf("添加产品到仓库,当前库存: %d: %s\n", storage.size(), object);
notifyAll();
}
/**
* 消费者从仓库中获取产品
* @return
*/
public Object get() {
Object object = null;
synchronized (this) {
//产品库存空了,消费者暂停消费
while(storage.size() == 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
object = ((LinkedList<Object>)storage).poll();
System.out.printf("从仓库获取产品,剩余库存: %d: %s\n", storage.size(), object);
notifyAll();
}
return object;
}
}
/**生产者*/
static class Producer implements Runnable{
/**消费者名称*/
private String name;
/**生产者产量*/
private int num;
/**仓库库存*/
private Storage storage;
public Producer(String name, int num, Storage storage) {
super();
this.name = name;
this.num = num;
this.storage = storage;
}
@Override
public void run() {
for(int i = 1; i <= num; i++){
storage.add(name + "生产的第" + i + "个产品");
}
}
}
/**消费者*/
static class Consumer implements Runnable{
/**消费者消费量*/
private int num;
/**仓库库存*/
private Storage storage;
public Consumer(int num, Storage storage) {
super();
this.num = num;
this.storage = storage;
}
@Override
public void run() {
for(int i = 0; i < num; i++){
Object object = storage.get();
System.out.println("取走了" + object);
}
}
}
public static void main(String[] args) throws InterruptedException {
Storage storage = new Storage(2);
Producer producer = new Producer("生产者" , 10, storage);
Thread thread1 = new Thread(producer);
Consumer consumer = new Consumer(10, storage);
Thread thread2 = new Thread(consumer);
thread2.start();
thread1.start();
Thread.sleep(1000);
}
}
2.2 Object之hashCode
Object的hashCode方法默认实现是native的
-
返回的是对象的地址
-
hashCode是可以被重写覆盖
注意事项:
-
重写了equals方法的类,都必须覆盖hashCode方法
-
因为不覆盖hashCode会违反一些类的设计准则
2.3 Object中equals
Object之equals方法:
-
默认实现是比较对象的引用是否指向同一个对象
-
equals可以被子类重写覆盖
默认equals比较原理:对于对象引用,==比较对象引用是否指向同一个对象。对于基本类型,比较实际内容。
public boolean equals(Object obj) {
return (this == obj);
}
equals应用场景
-
当需要编写自己的比对逻辑时
-
此时我们需重写equals方法
2.4 Object中clone
Object的clone的作用是创建并返回此对象的一个副本 方法时native的 此方法可被子类重写覆盖
protected native Object clone() throws CloneNotSupportedException;
当类未实现接口Cloneable,则会抛出CloneNotSupportedException
注意事项: 1.此方法是该对象的“浅复制”,而不“深复制”操作 浅拷贝:对于基本数据类型,复制其数据。对于对象引用,只是复制对象引用,而不是复制对象引用所指向的对象 2.由于Object类本身未实现接口Cloneable,所以在类为Object的对象上调用clone方法将会导致在运行时抛出异常
2.5 Object之toString
Object之toString方法的功能: 用于返回该对象的字符串表示 Object类的toString方法返回一个字符串 该字符串由类名(对象是该类的一个实例)、at标记符“@”和此对象哈希码的无符号十六进制表示组成
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
toString():返回对象的字符串表示。例如:
var obj = {name: "John", age: 25};
console.log(obj.toString()); // [object Object]
console.log(date.toString()); // 根据默认格式返回日期和时间字符串
2.6 Object之finalize
Object的finalize方法主要用于垃圾回收 此方法可以被子类重写覆盖。
protected void finalize() throws Throwable { }
-
当垃圾回收器确定不存在对该对象的更多引用时
-
由对象的垃圾回收器调用此方法
-
子类重写finalize方法,以配置系统资源或执行其他清除
-
该方法的执行通常是不可预测的,也非常危险的,笔者不推荐大家使用
2.7 Object类方法之notify和notifyAll方法
notify()方法表示,当前的线程已经放弃对资源的占有, 通知等待的线程来获得对资源的占有权,但是只有一个线程能够从wait状态中恢复,然后继续运行wait()后面的语句;只会唤醒等待该锁的其中一个线程。 notifyAll()方法表示,当前的线程已经放弃对资源的占有, 通知所有的等待线程从wait()方法后的语句开始运行; 唤醒等待该锁的所有线程。 对象内部锁 其实,每个对象都拥有两个池,分别为锁池(EntrySet)和(WaitSet)等待池。
2.7.1 锁池
锁池:假如已经有线程A获取到了锁,这时候又有线程B需要获取这把锁(比如需要调用synchronized修饰的方法或者需要执行synchronized修饰的代码块),由于该锁已经被占用,所以线程B只能等待这把锁,这时候线程B将会进入这把锁的锁池。
2.7.2 等待池
等待池:假设线程A获取到锁之后,由于一些条件的不满足(例如生产者消费者模式中生产者获取到锁,然后判断队列为满),此时需要调用对象锁的wait方法,那么线程A将放弃这把锁,并进入这把锁的等待池。
如果有其他线程调用了锁的notify方法,则会根据一定的算法从等待池中选取一个线程,将此线程放入锁池。 如果有其他线程调用了锁的notifyAll方法,则会将等待池中所有线程全部放入锁池,并争抢锁。
2.7.3 锁池与等待池的区别
锁池与等待池的区别:等待池中的线程不能获取锁,而是需要被唤醒进入锁池,才有获取到锁的机会。
例如: 有两个生产者A和B,两个消费者C和D,以及一个长度为1的队列。
初始状态,这四个线程全部进入锁池,等待抢占锁。 C获取到锁,但是队列为空,故C进入等待池。 D获取到锁,但是队列为空,故D进入等待池。 A获取到锁,生产,队列满,调用notify,唤醒一个线程。由于此时C和D都在等待池中,所以会有一个线程从等待池进入锁池,假设此处C进入锁池。 此时,锁池有B和C两个线程,假设B获取到了锁,但是队列满,故B进入等待池,放弃锁。 此时,C获取到锁,消费,notify,由于此时等待池有两个线程B和D,假如唤醒的是B,没问题开始生产,但是若唤醒的是D,则因队列为空,继续wait。
如果此处是一个生产者一个消费者的情况,使用notify没有任何问题,且效率更高。
2.8 hasOwnProperty(prop)
hasOwnProperty(prop):判断对象是否具有指定属性,返回布尔值。例如:
var obj = {name: "John", age: 25};
console.log(obj.hasOwnProperty("name")); // true
console.log(obj.hasOwnProperty("gender")); // false
2.9 isPrototypeOf(obj)
isPrototypeOf(obj):判断对象是否为另一个对象的原型。返回布尔值。例如:
var obj1 = {name: "John"};
var obj2 = Object.create(obj1);
console.log(obj1.isPrototypeOf(obj2)); // true
console.log(obj2.isPrototypeOf(obj1)); // false
2.10 propertyIsEnumerable(prop)
propertyIsEnumerable(prop):判断对象的属性是否可枚举,返回布尔值。例如:
var obj = {name: "John", age: 25};
console.log(obj.propertyIsEnumerable("name")); // true
console.log(obj.propertyIsEnumerable("toString")); // false
2.11 toLocaleString()
toLocaleString():返回对象的本地化字符串表示。例如:
var date = new Date();
console.log(date.toLocaleString()); // 根据本地化格式返回日期和时间字符串
2.12 valueOf()
valueOf():返回对象的原始值。例如:
var num = new Number(10);
console.log(num.valueOf()); // 10
最常用的Object方法是hasOwnProperty()、toString()和valueOf()。hasOwnProperty()用于判断对象是否具有指定属性,toString()用于返回对象的字符串表示,valueOf()用于返回对象的原始值。
小结:
-
Object对象是JavaScript中的顶级对象,是所有其他对象的基类。
-
Object对象具有一些通用的属性和方法,可以被所有其他对象继承和使用。
-
最常用的Object方法是hasOwnProperty()、toString()和valueOf()。
总结
以上就是今天的内容~
欢迎大家点赞👍,收藏⭐,转发🚀,
如有问题、建议,请您在评论区留言💬哦。
最后:转载请注明出处!!