# 3、线程间通讯与线程间定制化通讯

# 1、线程间通讯

# 1、new Thread().start()方法介绍

 public synchronized void start() {
      
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        group.add(this);

        boolean started = false;
        try {
        
        //在此处调用了start0的方法
        
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }
    
    
  //该方法由native修饰,掉起操作系统执行线程,但是此时如果操作系统不繁忙,则会掉起该线程,如果操作系统繁忙,则会等会在执行该线程
  private native void start0();
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

# 2、线程间通信

# 1、例子

定义一个初始值为0 ,假如有两个线程,线程a对初始值+1操作,线程b对初始值-1操作,依次执行线程a,线程b,即线程a执行一次,线程b执行一次,在线程a执行一次,在线程b执行一次......

下面的例子 aa/cc线程执行加法操作,bb/dd线程执行减法操作依次执行,但是aa/cc线程,或者bb/dd线程执行顺序不一定

package com.hjc.infor;

import java.util.concurrent.locks.ReentrantLock;

public class TestInfoSync {
    public static void main(String[] args) {
        A a = new A();

        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                a.add();
            }
      },"线程aa").start();

        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                a.del();
            }
        },"线程bb").start();
        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                a.add();
            }
        },"线程cc").start();

        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                a.del();
            }
        },"线程dd").start();
    }
}

class A{
    int a = 0;
    private final ReentrantLock lock = new ReentrantLock();
    public synchronized   void add(){
        if(a != 0){
            //当前进入该线程的线程等待
            this.wait();
        }
        a++;
        System.out.println(Thread.currentThread().getName()+"-->"+a);
        //唤醒当前进入该线程的线程
        this.notifyAll();
    }
    public synchronized void del(){
        if(a != 1){
            //当前进入该线程的线程等待
            this.wait();
        }
        a--;
        System.out.println(Thread.currentThread().getName()+"-->"+a);
        //唤醒当前进入该线程的线程
        this.notifyAll();
    }
}
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

# 2、虚假唤醒问题

上述例子存在虚假唤醒问题,this.wait()方法引发的问题,需要将if改成while

this.wait()在哪里睡就在哪里醒

# 1、案例解决 synchronized
package com.hjc.infor;

import java.util.concurrent.locks.ReentrantLock;

public class TestInfoSync {
    public static void main(String[] args) {
        A a = new A();

        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                a.add();
            }
      },"线程aa").start();

        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                a.del();
            }
        },"线程bb").start();
        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                a.add();
            }
        },"线程cc").start();

        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                a.del();
            }
        },"线程dd").start();
    }
}

class A{
    int a = 0;
    private final ReentrantLock lock = new ReentrantLock();
    public synchronized   void add(){
            while (a != 0){
                //当前进入该线程的线程等待
                this.wait();
            }
            a++;
            System.out.println(Thread.currentThread().getName()+"-->"+a);
            //唤醒当前进入该线程的线程
            this.notifyAll();
    }
    
    public synchronized void del(){
         while(a != 1){
             //当前进入该线程的线程等待
             this.wait();
         }
         a--;
         System.out.println(Thread.currentThread().getName()+"-->"+a);
         //唤醒当前进入该线程的线程
         this.notifyAll();

    }
}
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
# 2、案例解决 lock

private final ReentrantLock lock = new ReentrantLock(); Condition condition = lock.newCondition(); //Condition中有await等待和signalAll/signal唤醒方法

package com.hjc.infor;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class TestInfoSync {
    public static void main(String[] args) {
        A a = new A();

        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                a.add();
            }
      },"线程aa").start();

        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                a.del();
            }
        },"线程bb").start();
        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                a.add();
            }
        },"线程cc").start();

        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                a.del();
            }
        },"线程dd").start();
    }
}

class A{
    int a = 0;
    private final ReentrantLock lock = new ReentrantLock();
    Condition condition = lock.newCondition();
    //Condition中有await等待和signalAll/signal唤醒方法
    public void add(){
        lock.lock();
        try {
            while (a != 0){
                //当前进入该线程的线程等待
                condition.await();
            }
            a++;
            System.out.println(Thread.currentThread().getName()+"-->"+a);
            //唤醒当前进入该线程的线程
            condition.signalAll();


        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }
    public void del(){
        lock.lock();
        try {
            while (a != 1){
                //当前进入该线程的线程等待
                condition.await();
            }

            a--;
            System.out.println(Thread.currentThread().getName()+"-->"+a);
            //唤醒当前进入该线程的线程
            condition.signalAll();

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }
}

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
# 3、解决方法

将线程等待方法写在while循环中,避免在哪里等待就在哪里唤醒,导致判断失效往后执行的问题

# 2、线程间的定制化通信

# 1、例子

启动三个线程,AA线程打印5此,BB线程打印10次,CC线程打印15次,进行10轮

package com.hjc.infor;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TestDingZhi {
    public static void main(String[] args) {
        ShareResource shareResource = new ShareResource();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                shareResource.print5(i);
            }
        },"aa").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                shareResource.print10(i);
            }
        },"bb").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                shareResource.print15(i);
            }
        },"cc").start();
    }

}

class ShareResource{
    private int flag = 1;
    private Lock lock = new ReentrantLock();

    private Condition c1 = lock.newCondition();
    private Condition c2 = lock.newCondition();
    private Condition c3 = lock.newCondition();


    public void print5(int time){
        lock.lock();
        try {
            while ( flag!=1 ){
                c1.await();
            }
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName()+"::"+i+"::"+time);
            }
            flag = 2;
            c2.signalAll();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }
    public void print10(int time){
        lock.lock();
        try {
            while ( flag!=2 ){
                c2.await();
            }
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName()+"::"+i+"::"+time);
            }
            flag = 3;
            c3.signalAll();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }
    public void print15(int time){
        lock.lock();
        try {
            while ( flag!=3 ){
                c3.await();
            }
            for (int i = 0; i < 15; i++) {
                System.out.println(Thread.currentThread().getName()+"::"+i+"::"+time);
            }
            flag = 1;
            c1.signalAll();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }


}

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
90
91
92
93
94

#

上次更新: 2024/4/13