阳光下的少年 发表于 2019-2-4 20:27

[笔记] Java多线程synchronized,wait和notify的使用

# Java多线程synchronized,wait和notify的使用

## 前言
* 这段时间再看Java多线程,后面的wait()和notify()总是不知道什么时候用或者说怎么用
* synchronized虽然知道这个的用法,但是却不知道在哪里使用合适
* 今天晚上看了一篇文章,然后自己分析了一下,终于搞懂了,这篇帖子分享给有和我一样问题的小伙伴.
***
``` Java
public class DemoNumberLimit{
    public static void main(String args[]){
      Object obj = new Object();
      Thread threadOne = new Thread(){
            public void run(){
                for (int i=0;i<50;i++){
                  System.out.println(Thread.currentThread().getName()+":"+i);
                  try{
                        Thread.sleep(500);
                  }
                  catch(InterruptedException e){
                        e.printStackTrace();
                  }
                }
                //华丽的分割线
                for(int i=0;i<50;i++)
                  System.out.print("=");
                System.out.println();       //换行
                //同步
                synchronized(obj){
                  obj.notify();
                }
                System.out.println("第一个线程接着执行");
                for(int i = 51;i<101;i++){
                  System.out.println(Thread.currentThread().getName()+":"+i);
                  try{
                        Thread.sleep(500);
                  }
                  catch(InterruptedException e){
                        e.printStackTrace();
                  }
                }
                System.out.println("线程1执行完成");
            }
      };
      //线程2
      Thread threadTwo = new Thread(){
            public void run(){
                synchronized(obj){
                  try{
                        obj.wait();
                  }
                  catch(InterruptedException e){
                        e.printStackTrace();
                  }
                  System.out.println("线程2:");
                  System.out.println("线程1的上半部分执行完成,开始执行下半部分");
                }
            }
      };
      threadOne.start();
      threadTwo.start();
      threadOne.setName("One");
      threadTwo.setName("Two");
    }
}
```
* 我在这里贴出运行结果图,帮助大家理解
``` Java
One:0
One:1
One:2
One:3
One:4
One:5
One:6
One:7
One:8
One:9
One:10
One:11
One:12
One:13
One:14
One:15
One:16
One:17
One:18
One:19
One:20
One:21
One:22
One:23
One:24
One:25
One:26
One:27
One:28
One:29
One:30
One:31
One:32
One:33
One:34
One:35
One:36
One:37
One:38
One:39
One:40
One:41
One:42
One:43
One:44
One:45
One:46
One:47
One:48
One:49
==================================================
第一个线程接着执行
线程2:
线程1的上半部分执行完成,开始执行下半部分
One:51
One:52
One:53
One:54
One:55
One:56
One:57
One:58
One:59
One:60
One:61
One:62
One:63
One:64
One:65
One:66
One:67
One:68
One:69
One:70
One:71
One:72
One:73
One:74
One:75
One:76
One:77
One:78
One:79
One:80
One:81
One:82
One:83
One:84
One:85
One:86
One:87
One:88
One:89
One:90
One:91
One:92
One:93
One:94
One:95
One:96
One:97
One:98
One:99
One:100
线程1执行完成
```
* 代码分析:
        1. 首先看看```threadOne```这个线程里面的```synchronized```从这里开始一直到```threadTwo```线程的大括号结束,可以看做是一整块代码块.
        2. 然后因为```synchronized```和下面的线程2是一个整体所以会先执行线程2里面的两条输出语句,然后在执行线程1中后面那个for循环
* 这些仅仅是我个人理解,如有不足请留言指出.
***
* 其他问题:
        1. 线程1的```synchronized```语句后面的输出语句**第一个线程接着执行**为什么跳过for循环直接执行了线程2然后在执行线程1中的for循环.
        2. 为什么要先写```notify()```然后在写```wait()```

唯我独宅 发表于 2019-2-4 20:58

{:301_993:}过年了,还在努力学习。

demon_lin 发表于 2019-2-5 23:08

谢谢分享

天使3号 发表于 2019-7-29 01:17

本帖最后由 天使3号 于 2019-7-29 01:19 编辑

1.线程1的synchronized语句后面的输出语句第一个线程接着执行为什么跳过for循环直接执行了线程2然后在执行线程1中的for循环.
恰巧!
给你看我的执行结果:
One:48
One:49
==================================================
第一个线程接着执行
One:51
线程2:
线程1的上半部分执行完成,开始执行下半部分
One:52
One:53
One:54
从threadOne的synchronized的右}结束,这时的threadOne就释放了互斥变量obj,此时threadOne和threadTwo已经随CPU分配的时间片随机并发执行了。
虽然threadTwo好像是在synchronized代码块中,但是它锁住的是obj互斥变量,在threadOne中并不需要obj也不锁住它了。就是个并发执行的随机结果。

2.为什么要先写notify()然后在写wait()
不对,从这里的执行看,是先在threadTwo中执行的obj.wait(),释放了obj这个互斥变量,等待被唤醒(notify)。
因为在threadOne中前面太多要执行的代码,又人为的让它sleep了很久,所以从结果上看obj.notify()是在obj.wait()之后才执行的。
如果先执行了nofity,那么第二个线程的wait将永远不能被唤醒!


3.我今年过年的时候就看了你这篇文章,当时懵逼不懂并发,近段时间学的,如有不对,多多指教!

一夜梦惊人 发表于 2019-7-29 15:31

我来进行彻底讲解一下。首先贴上我的运行结果关键部分。
==================================================
第一个线程接着执行
One:51
线程2:
线程1的上半部分执行完成,开始执行下半部分
One:52
One:53
为什么会不一样呢?
首先这个====这里毋庸置疑是正确的,必须会在49的后面,然后synchronized哪里进行notify,而threadTwo而是另一个线程,在接到notify后,wait就会失效然后继续执行。此时你看作是一整块代码这个思想是错误的,因为两个代码在语意上是同时执行。由于CPU设计的问题才会给你这种错觉,就像一个人处理事情一样,他所谓的同时执行,其实就是做一点这件事然后又去做另一件事,看起来就是两件事同时在做。换句话说就是两块代码之间选一个随机执行,这是看运气问题,然后由于线程2后续消耗的时间极短,看起来就像是处理完线程2后才又执行的线程1。

还有一个问题,为什么你觉得要先执行nofity才行呢?那是因为你被代码所误导了,两个线程几乎同时开始,而你的线程1却在不断的sleep,这导致的就是你其实先执行了,线程2的wait。我就说到这里,你可以自行修改代码进行实验。

笑海的星星 发表于 2019-7-29 18:05

线程一和二基本上同时执行,只不过线程二等待,当线程一运行notify时,两个线程同时抢执行权,然后两个线程谁先执行谁后执行就是随机的了。没有哪个是确定的。
页: [1]
查看完整版本: [笔记] Java多线程synchronized,wait和notify的使用