Android/JAVA 笔记 同步操作/synchronized / wait()/ notify()

时间:2022-06-09 23:49:12

synchronized

编写程序离不开多线程操作。而多线程又离不开同步操作。这是很重要的。

java语言有一个关键词synchronized可以应多同步操作。之前学习的时候我没有怎么去理解这个东西。最近在研究延迟操作和animator的时候顺便把这个弄清白了,就在这里记录一下。

  1. 可以对一个方法标记,那么每次就只有一个线程能进入这个方法
  2. 对一个代码块标记,同上。而且对代码块标记的时候会指定一个对象,是为被加锁对象。如果有其他的被标记的代码块也指定同一个对象的话,那么这些代码块同时也被加锁。所以重点就是被加锁的是对象
  3. 对一个静态方法标记,那么这个静态方法为同步方法,所有该类的对象的此静态方法都会被加锁。(这是静态方法的特性,很好理解)
  4. 对一个class标记,那么这个class的所有对象都会被加锁。标记类的方式与标记代码块相同,但是括号里面的是类似ClassName.class

目前查找到的资料是这样写的。

Object object = new Object();
synchronized(object) {
``````
}

另外某个地方
synchronized(object) {
``````
}

正如上面描述的,刚才这段代码里面有两个代码块被synchronized,并且标记同一个对象为锁。如果两个线程分别使用两个代码块,那么他们也会被加锁,每次只有一个能调用,另外一个需要等待。
所以说,并非只有进入同一个代码块才需要同步等待,只要进入的代码块是被同一个对象加锁的,都需要等待。

其他的倒是很好理解。
参考 1
参考 2

notify() / wait() / notifyAll()

有些任务需要线程同步操作一个对象的内容,类似生产者 / 消费者的模型
例如对一个List,一个线程添加内容,另一个线程读取里面的内容,这就是最简单的生产者/消费者模型。
为了防止在操作没有完全的时候就开始读取,需要对这个list对象加锁,也就是启用synchronized。

而消费者线程,需要不停的查询List的内容,如果为空就继续查询,如果有内容就开始读取并显示出来。
一般我们会考虑用while(true)循环来工作,但是这样会造成cpu资源的浪费,因为一直在查询操作。
或者我们不是需要立即显示,我们需要的是等待被通知以后再显示。

这时候可以用到wait() / notify()

首先明确一点就是这两个函数只能在同步代码块/方法里面使用。
当对被锁的对象使用wait()的时候,进入该代码块的线程会被挂起,不再运行,不再占用cpu资源。并且释放该对象的锁。
这收其他的因为该对象被加锁而等待的线程可以开始运行了。
如果某个时候其他活动线程对该对象调用notify(),那么刚才被挂起的线程可以重新开始运行。
有一点需要注意就是永远在while()循环里面调用wait()而不是if()里面,这样可以持续检查是否满足条件。

这就是wait()/notify()。是不是很神奇。

另外还有一个notifyAll(),那么他们的区别是什么呢?

  • notify()只通知一个被挂起的线程开始工作,并且他不知道那个被通知。
  • notifyAll()通知所有被挂起的线程开始工作。

使用这个方法,对一个对象置入信息以后另外一个去读取,可以实现线程通信。
当然,实现线程通信有很多更加便捷的类,android里面更是简单的多。
多一个选择总是没有错的。

参考 如何在 Java 中正确使用 wait, notify 和 notifyAll