这里将线程间通信的途径分为两类:同享内存和消息传递。

  • 同享内存
  1. volatile关键字的使用

就是利用volatile关键字的可见性,多个线程对它进行监控在其变量发生变化后执行对应线程的操作。

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
class ThreadCommunication {
public static int STATE_RUN_A = 0;
public static int STATE_RUN_B = 1;
public static int STATE_RUN_C = 2;

volatile static int state = STATE_RUN_A;
static int counter = 1;

public static void main(String[] args) {

Thread threadA = new Thread(new Runnable() {
@Override
public void run() {
try {
//这里睡眠3s等待BC线程
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int c = 1 << 3;
if (state == STATE_RUN_A) {
System.out.println("threadA is running!");
for (int i = 0; i < c; i++) {
if (i == 5) {
state = STATE_RUN_B;
break;
}
}
}
}
});

Thread threadB = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
if (state == STATE_RUN_B) {
System.out.println("threadB is running!");
do {
counter = counter << 1;
} while (counter < 1 << 4);

state = STATE_RUN_C;
break;
}
}
}
});

Thread threadC = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
if (state == STATE_RUN_C) {
System.out.println("threadC is running!");
do {
counter = counter >> 1;
} while (counter > 1);

System.out.println("threadC finish counter:" + counter);
break;
}
}
}
});

threadA.start();
threadB.start();
threadC.start();
}
}

  • 消息传递
  1. Object.wait()\notify()

在线程中调用该线程锁对象是wait方法是,该线程就被放入等待队列,直到被其他线程通知notify。

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
class ThreadCommunication {
static int counter = 1;
static Object lock = new Object();

public static void main(String[] args) {

Thread threadB = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
synchronized (lock) {
System.out.println("threadB is running!");

do {
counter = counter << 1;
} while (counter < 1 << 4);
lock.notify();
break;
}
}
}
});

Thread threadC = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
synchronized (lock) {
if (counter == 1 << 4) {
System.out.println("threadC is running!");
do {
counter = counter >> 1;
} while (counter > 1);

System.out.println("threadC finish counter:" + counter);
break;
} else {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
});

threadC.start();
threadB.start();
}
}

  1. .join() {Thread.join}

当一个线程调用另外一个线程的join方法时,当前的线程就会阻塞等待被调用join方法的线程执行完毕后才能继续执行,所以join方法用来保证线程执行的顺序。

  1. CountDownLatch类

CountDownLatch类可以使线程等待其他线程执行完毕后再执行。
通过一个计数器来实现,CountDownLatch初始化传入的count代表等待count个线程执行完毕后等待的线程才能恢复执行。一般有几个应用场景:
场景一:
有多个线程依赖其他多个线程的执行完的结果,这是等待的await,被等待的线程执行完调用coutdown然后计数器减一,直到减为0就恢复多个线程的执行;
场景二:
实现多个线程同时执行,多个线程都设置await coutdown设置为1 在主线程中调用countdown让多个线程同时执行运行。

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
class ThreadCommunication {
static int counter = 1;
static CountDownLatch countDownLatch = new CountDownLatch(2);

public static void main(String[] args) {

Thread threadA = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("threadA await");
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("threadA is running!");

}
});

Thread threadB = new Thread(new Runnable() {
@Override
public void run() {
countDownLatch.countDown();
System.out.println("threadB is running!");
}
});

Thread threadC = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
do {
counter = counter << 1;
System.out.println("threadC is running! counter=" + counter);

} while (counter < 1 << 5);

countDownLatch.countDown();
break;
}
}
});

threadA.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
threadB.start();
threadC.start();
}
}

  1. LockSupport类
    LockSupport是JDK中用来实现线程阻塞和唤醒的工具。使用它可以在任何场合使线程阻塞,可以指定任何线程进行唤醒。
    LockSupport的设计核心是“许可”,park是等待一个许可,unpark是为某一线程提供一种许可,如果某线程A调用park,那么除非另外一个线程调用unpark(A)给A一个许可,否则线程A将阻塞在park操作上。还有就是unpark可以在park前调用,也就是先提供许可,等到后面调用park时在消耗之前的许可。
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
class ThreadCommunication {

public static void main(String[] args) {

Thread threadA = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("threadA park");
LockSupport.park();
System.out.println("threadA is running!");

}
});

Thread threadB = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("threadB park");
LockSupport.park();
System.out.println("threadB is running!");

System.out.println("threadB unpark threadA");
LockSupport.unpark(threadA);
}
});

threadA.start();
threadB.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main thread unpark threadB");
LockSupport.unpark(threadB);
}
}