惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 聂微东
S
Secure Thoughts
P
Palo Alto Networks Blog
Google DeepMind News
Google DeepMind News
AI
AI
H
Hacker News: Front Page
Schneier on Security
Schneier on Security
C
CXSECURITY Database RSS Feed - CXSecurity.com
Cloudbric
Cloudbric
TaoSecurity Blog
TaoSecurity Blog
T
Tor Project blog
L
LINUX DO - 热门话题
Cyberwarzone
Cyberwarzone
V2EX - 技术
V2EX - 技术
Google DeepMind News
Google DeepMind News
GbyAI
GbyAI
S
Security @ Cisco Blogs
S
Security Affairs
P
Privacy International News Feed
I
Intezer
S
SegmentFault 最新的问题
F
Full Disclosure
H
Heimdal Security Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
S
Securelist
V
Vulnerabilities – Threatpost
C
CERT Recently Published Vulnerability Notes
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Google Online Security Blog
Google Online Security Blog
Security Latest
Security Latest
C
Cybersecurity and Infrastructure Security Agency CISA
Attack and Defense Labs
Attack and Defense Labs
Forbes - Security
Forbes - Security
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
I
InfoQ
WordPress大学
WordPress大学
Vercel News
Vercel News
小众软件
小众软件
大猫的无限游戏
大猫的无限游戏
美团技术团队
IT之家
IT之家
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
aimingoo的专栏
aimingoo的专栏
Y
Y Combinator Blog
Last Week in AI
Last Week in AI
博客园 - 【当耐特】
D
Docker
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Hugging Face - Blog
Hugging Face - Blog

卡瓦邦噶!

服务器高性能网络调优 | 卡瓦邦噶! 为何写作 | 卡瓦邦噶! 读《金阁寺》 | 卡瓦邦噶! 雨季又来 | 卡瓦邦噶! MTU Probe 引起的初始延迟 | 卡瓦邦噶! 3.5 秒的固定延迟问题 | 卡瓦邦噶! 学习网络的一点经验 | 卡瓦邦噶! ARP 问题诊断 | 卡瓦邦噶! 网络断断续续…… | 卡瓦邦噶! Piccolo P2P 镜像分发 | 卡瓦邦噶! 一起看电影 | 卡瓦邦噶! 《征服C指针》 | 卡瓦邦噶! 我的姥姥 | 卡瓦邦噶! WordPress网站迁移方案 Python的哲学 Python 3.5的新特性 学校不教的计算机课 垃圾回收(GC)的三种基本方式 在编程中体验纯粹的快乐 从《美丽新世界》谈自由 在快钱实习 迷人的嗓音和迷人的故事——《Sleepyhead》 Python 的十个自然语言处理工具 记一个愚蠢的bug 一年炉石传说的游戏体验 《以撒的结合:重生》网页版图鉴 分清 C++的指针、引用和数组 笑话三则 自由比皇帝更伟大——《悲惨世界》笔记 Git 10 周年访谈:Linus 讲述背后故事 用 0x3f3f3f3f 设定最大int值的优点 Joel给计算机系学生的建议 一个词法分析器的简单实现 怎样才算健康的生活方式 MacVim 配置攻略 学习培训课程的视频效果好吗? 语言的控制 可悲的大多数 CSS样式思维导图 2014年终总结 奥巴马成为首位写程序的美国总统 青岛老城区的下水道好在哪里? 做优秀 UI 的七个建议(第二部分) 选择爱情的骑士 Git简明教程 Java集合总览 读 《1984》 Java 问答:终极父类(五)——toString() Hyperlapse快速视频背后的技术细节 平庸之恶 Java程序员须知的七个日志管理工具 苏州 逛书摊随想 关于考试作弊 你的工作不仅仅是编程 推荐在线学习Java的英文资源 关注女性命运——《千禧年三部曲》 用好你的幻灯片——《演说之禅》 使用ReentrantLock和Lambda表达式让同步更纯净 新手学编程,从哪里开始? 程序员都是工程师吗? 不要学习代码,要学会思考 Java 问答:终极父类(四)——hashCode() Java 问答:终极父类(三)——finalize()和 getClass() 程序员职业之路的选择 我是一名摄影家 写给何小树的城市指南 为什么一些语言会比别的快? Java的常见误区与细节 跟朋友在一起玩游戏 死神永生——读《三体》 五种类型的程序员 创业圣经——读《黑客与画家》 纪念加西亚·马尔克斯 Junit中处理异常的另一种方式:catch-exception Java8采用Martin Fowler的方法创建内部DSL Linux HotSopt虚拟机GC线程的CPU占用率 J2EE概念介绍 如何成为一名黑客 Java 问答:终极父类(二)——equals()方法 为什么我喜欢Java Java 问答:终极父类(一)——clone()方法 七个改变世界的Java项目 java中默认类型转换的小问题 传统与创新 欢迎来到互联网 莫言和马尔克斯——读《生死疲劳》 位运算的妙用 读《人为什么活着》 写博客教会我的事情 中国特色操作系统 2013年总结 《永不妥协》影评 恨不相逢未嫁时——《廊桥遗梦》影评 如何优雅地使用PPT 给明年依然年轻的我们 天才与柱子 黑客守则和黑客精神 Looking for Freedom——《被解救的姜戈》 简洁之道
java问答:终极父类(六)——等待/唤醒和接口
laixintao · 2014-09-26 · via 卡瓦邦噶!

等待和唤醒

Qwait()notify()  notifyAll() 是用来干什么的?

Await()notify()  notifyAll() 可以让线程协调完成一项任务。例如,一个线程生产,另一线程消费。生产线程不能在前一产品被消费之前运行,而应该等待前一个被生产出来的产品被消费之后才被唤醒,进行生产。同理,消费线程也不能在生产线程之前运行,即不能消费不存在的产品,所以应该等待生产线程执行一个之后才执行。利用这些方法,就可以实现这些线程之间的协调。从本质上说,一个线程等待某种状态(例如一个产品被生产),另一个线程正在执行,知道产生了某种状态(例如生产了一个产品)。

Q:不同的 wait() 方法之间有什么区别?

A:没有参数的 wait() 方法被调用之后,线程就会一直处于睡眠状态,直到本对象(就是 wait() 被调用的那个对象)调用 notify()  notifyAll() 方法。相应的,wait(long timeout) wait(long timeout, int nanos) 方法中,当等待时间结束或者被唤醒(无论哪一个先发生)时将会结束等待。

Qnotify()  notifyAll() 方法有什么区别?

Anotify() 方法随机唤醒一个等待的线程,而 notifyAll() 方法将唤醒所有在等待的的线程。

Q:线程被唤醒之后会发生什么?

A:当一个线程被唤醒之后,不会立即执行,除非本对象(调用 notify()  notifyAll() 的对象)的同步锁被释放。唤醒的线程会按照规则和其他线程竞争同步锁,得到锁的线程将执行。所以 notifyAll() 方法执行之后,可能会有一个线程立即运行,也可能所有的线程都没运行。

Q:为什么在使用等待、唤醒方法时,要放在同步代码中?

A::将等待和唤醒方法放在同步代码中是非常必要的,这样做是为了避免出现竞争条件。鉴于要等待的线程通常在调用wait()之前会确认一种情况存在与否(通常是检查某一变量的值),而另一线程在调用notify()` 之前通常会设置某种情况(通常是通过设置一个变量的值)。以下的这种情况就是发生了竞争条件:

  1. 线程一检查了情况和变量,发现需要等待。
  2. 线程二设置了变量。
  3. 线程二调用了 notify() 。此时,线程一还没有等待,所以这次调用什么用都没有。
  4. 线程一调用了 wait()。这下它永远不会被唤醒了。

Q:如果在同步代码之外使用这些方法会怎么样呢?

A:如果在同步代码之外使用了这些情况,就会跑出java.lang.IllegalMonitorStateException异常。

Q:如果在同步代码中调用这些方法呢?

A:当 wait() 方法在同步代码中被调用时,会根据同步代码中方法的优先级先后执行,在 wait() 方法返回值之前,该同步代码一直持有锁,这样就不会出现竞争条件了。在 wait() 方法可以接受唤醒之前,锁一直都不会被释放。

Q:为什么要要把 wait() 的调用放在 while 循环中,而不是 if 判断中呢?

A:为了防止假唤醒,可以在 stackoverflow 上了解有关这类现象的更多信息——假唤醒真的会发生吗?

Q:能提供一个使用等待与唤醒方法的范例吗?

A:见代码清单2.

代码清单2

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

public class WaitNotifyDemo

{

   public static void main(String[] args)

   {

      class Shared

      {

         private String msg;

         synchronized void send(String msg)

         {

            while (this.msg != null)

               try

               {

                  wait();

               }

               catch (InterruptedException ie)

               {

               }

            this.msg = msg;

            notify();

         }

         synchronized String receive()

         {

            while (msg == null)

               try

               {

                  wait();

               }

               catch (InterruptedException ie)

               {

               }

            String temp = msg;

            msg = null;

            notify();

            return temp;

         }

      }

      final Shared shared = new Shared();

      Runnable rsender;

      rsender = new Runnable()

                {

                   @Override

                   public void run()

                   {

                      for (int i = 0; i < 10; i++)

                      {

                         shared.send("A"+i);

                         try

                         {

                            Thread.sleep((int)(Math.random()*200));

                         }

                         catch (InterruptedException ie)

                         {

                         }

                      }

                      shared.send("done");

                   }

                };

      Thread sender = new Thread(rsender);

      Runnable rreceiver;

      rreceiver = new Runnable()

                  {

                     @Override

                     public void run()

                     {

                        String msg;

                        while (!(msg = shared.receive()).equals("done"))

                        {

                           System.out.println(msg);

                           try

                           {

                              Thread.sleep((int)(Math.random()*200));

                           }

                           catch (InterruptedException ie)

                           {

                           }

                        }

                     }

                  };

      Thread receiver = new Thread(rreceiver);

      sender.start();

      receiver.start();    

   }

}

代码清单2:发送与接收信息

代码清单2声明了一个 WaitNotifyDemo 类,其中,main() 方法有一对发送和接收信息的线程。

main() 方法首先声明了 Shard 本地类,包含接收和发送信息的任务。Share 声明了一个 String 类型的smg 私有成员变量来存储要发送的信息,同时声明了同步的 send()  receive() 方法来执行接收和发送动作。

发送线程调用的是 send()。因为上一次调用 send() 的信息可能还没有被接收到,所以这个方法首先要通过计算 this.msg != null 的值来判断信息发送的状态。如果返回值为真,那么信息处于被等待发送的状态,就会调用 wait() ,一旦信息被接收到,接受的线程就会给 msg 赋值为 null ,并存储新信息,调用notify() 唤醒等待的线程。

接收线程调用的是 receive() 因为可能没有信息处于被接收状态,这个方法首先会通过计算 mas == null的值来验证信息有没有等待被接收的状态。如果表达式返回值为真,就表示没有信息等待被接收,此线程就要调用 wait() 方法。如果有信息发送,发送线程就会给 msg 分配值并且调用 notify() 唤醒接收线程。

编译(javac WaitNotifyDemo.java)并运行(java WaitNotifyDemo)源代码,将会看到以下输出结果:

代码清单2 输出结果

Java

1

2

3

4

5

6

7

8

9

10

A0

A1

A2

A3

A4

A5

A6

A7

A8

A9

Q:我想更加深入的学习等待和唤醒的机制,能提供一些资源吗?

A:可以在 artima 参考 Bill Venners 的书《Inside the Java Virtual Machine(深入理解 java 虚拟机)》中第20章 Chapter 20: Thread Synchronization.

Object,接口和 java8

Q:在第一部分中提到过接口是不继承 Object 的。然而,我发现有些接口中声明了 Object 中的方法。比如,java.util.Comparator 接口有 boolean.equals(Object.obj).为什么呢?

A:Java语言规范的 9.6.3.4 部分中清楚说明了,接口有相当于 Object 中成员那样的公共抽象成员。此外,如果接口中声明了 Object 中的成员函数(例如,声明的函数相当于覆盖 Object 中的 public 的方法),则认为是接口覆盖了他们,可以用 @Orride注释。

为什么要在接口中声明 public 的非final object 方法(可能还带有 @Override)呢?举例来说,Comparator 接口中就有 boolean equals(Object obj) 声明,这个方法在接口中声明是为了此接口的特殊情况。

此外,这个方法只有在传入的类是一个比较规则相同的比较器的时候,才能返回 true

因为这种情况是可选的,所以并不强制实现 Comparator,这取决于有没有 equals只有在遇到一个比较规则相同的比较器的时候才返回真的需求。尽管类并不要求覆盖 equals,但是文档中却支持这样做来提高性能。

注意,不覆盖 Object.equals(Object)是安全的,但是覆盖这个方发可能在一些情况下提高性能,比如让程序判断两个不同的比较器是不是用的相同的规则。

Q:哪一个 Employee 方法被覆盖了?是 Object 中的,还是接口中的?

A:更早的文档中说,被覆盖的方法是 Object 中的。

Q:java 8支持接口中的默认方法。可以在接口中默认实现 Employee 方法或者 Object 中的其他方法吗?

A:不可以。Object中的任何 public的非 final 方法都是不允许在接口中默认实现的。这个限制的基本原理在 Brian Goetz 的 允许默认方法覆盖Object中的方法 一文中有说明。

Q:能提供更多关于接口中 Object 方法的学习资源吗?

A:可以参考这篇 接口继承了 Object 类吗?

—-

至此,所有有关 Object 的介绍就结束了。查看目录请看第一部分