前言:
大家好,我是Felix,相信有过面试经验的朋友都知道,线程之前的通信经常会作为面试的笔试题来考察大家,但是,你知道有多少种方式可以实现嘛,今天来整理一下。
比如说我们现在要实现两个线程轮流打印AB
- 通过java的内置锁来实现
小知识补充:很多时候,提到内置锁,很多人不知道是什么,其实内置锁就是synchronized, 这就是JAVA设计之初自带的解决多线程的方案,而后序的JUC(java并发包)是java后期,其他作者去写的。
package mutiflyThread;
/**
* 首先要新建一个资源类,多线程操作要和资源类区分开来
* 可以看到一个资源类应该很干净,没有多余的东西
*/
public class Data {
private int flag = 0;
public synchronized void printA() throws InterruptedException {
while (flag != 0) {
this.wait();
}
System.out.println(String.format("当前线程:%s, 打印:A,当前flag: %s",Thread.currentThread().getName(), flag));
flag ++;
this.notifyAll();
}
public synchronized void printB() throws InterruptedException {
while (flag != 1) {
this.wait();
}
System.out.println(String.format("当前线程:%s, 打印:B,当前flag: %s",Thread.currentThread().getName(), flag));
flag --;
this.notifyAll();
}
}
package mutiflyThread;
/**
* 首先要新建一个资源类,多线程操作要和资源类区分开来
* 可以看到一个资源类应该很干净,没有多余的东西
*/
public class Data {
private int flag = 0;
public synchronized void printA() throws InterruptedException {
while (flag != 0) {
this.wait();
}
System.out.println(String.format("当前线程:%s, 打印:A,当前flag: %s",Thread.currentThread().getName(), flag));
flag ++;
this.notifyAll();
}
public synchronized void printB() throws InterruptedException {
while (flag != 1) {
this.wait();
}
System.out.println(String.format("当前线程:%s, 打印:B,当前flag: %s",Thread.currentThread().getName(), flag));
flag --;
this.notifyAll();
}
}
小技巧:在编写这种线程通信的代码时候,他们总是遵循这种编程技巧
- 首先在while条件中写入线程等待的代码
- 后面紧跟着业务代码
- 唤醒其他线程
- 更改线程之前通信的flag
可以好好琢磨下,是不是这个道理。
- 通过JUC下的ReentrantLock
其实也是有对应关系的,如果使用synchronized,我们是通过wait()和notify()方法来通信线程的, 但是如果用了Lock锁,他们的通信就是使用condition.await(),condition.single()。如果这样对比去学习可能记忆会更加深刻。
package mutiflyThread;
/**
* 首先要新建一个资源类,多线程操作要和资源类区分开来
* 可以看到一个资源类应该很干净,没有多余的东西
*/
public class Data {
private int flag = 0;
public synchronized void printA() throws InterruptedException {
while (flag != 0) {
this.wait();
}
System.out.println(String.format("当前线程:%s, 打印:A,当前flag: %s",Thread.currentThread().getName(), flag));
flag ++;
this.notifyAll();
}
public synchronized void printB() throws InterruptedException {
while (flag != 1) {
this.wait();
}
System.out.println(String.format("当前线程:%s, 打印:B,当前flag: %s",Thread.currentThread().getName(), flag));
flag --;
this.notifyAll();
}
}
package mutiflyThread;
/**
* 通过java内置锁的方式实现
*/
public class MethodTwo {
public static void main(String[] args) {
DataNew data = new DataNew();
Thread threadA = new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.printA();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A线程");
Thread threadB = new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.printB();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B线程");
threadA.start();
threadB.start();
}
}
- 通过信号量的方式来实现
可以发现信号量的方式非常简单
package mutiflyThread;
import java.util.concurrent.Semaphore;
/**
* 通过信号量的方式实现
*/
public class MethodThree {
public static void main(String[] args) {
Semaphore semaphoreA = new Semaphore(1);
Semaphore semaphoreB = new Semaphore(1);
Thread A = new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
semaphoreB.release();
System.out.println(String.format("当前线程:%s, 打印:A",Thread.currentThread().getName()));
semaphoreA.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A");
Thread B = new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
semaphoreA.release();
System.out.println(String.format("当前线程:%s, 打印:B",Thread.currentThread().getName()));
semaphoreB.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B");
A.start();
B.start();
}
}