求一个 Java 面试题的最佳实践

2021-01-25 12:24:37 +08:00
 Cbdy

三个线程,分别输出 a 、b 、c,各输出 100 次,要求按 abc 的顺序输出

期待输出为:abcabcabcabc...

4683 次点击
所在节点    Java
48 条回复
Yi23
2021-01-25 12:47:01 +08:00
第一反应可以使用 lock.condition 实现,3 个线程每个线程打印自己的字符,然后唤醒下一个线程。
线程 1 的方法类似如下
类似这样
```
lock.lock();
while (n != a) {
condition1.await(); // 线程 1 阻塞
}
// 输出 n
n = b; // 修改 n=b 然后唤醒线程 2
condition2.signal();
lock.unlock();
```
chenshun00
2021-01-25 13:00:29 +08:00
public static void main(String[] args) {

final Object xx1 = new Object();
final Object xx2 = new Object();
final Object xx3 = new Object();
Thread a = new Thread(() -> {

try {
synchronized (xx1) {
xx1.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
int a1 = 0;
while (a1 < 100) {
System.out.print("a");
a1++;

synchronized (xx2) {
xx2.notify();
}
try {
synchronized (xx1) {
xx1.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
a.setDaemon(true);
a.setName("aaa");
Thread b = new Thread(() -> {
try {
synchronized (xx2) {
xx2.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
int b1 = 0;
while (b1 < 100) {
System.out.print("b");
b1++;
synchronized (xx3) {
xx3.notify();
}
try {
synchronized (xx2) {
xx2.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
b.setDaemon(true);
b.setName("bbb");
Thread c = new Thread(() -> {
try {
synchronized (xx3) {
xx3.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
int c1 = 0;
while (c1 < 100) {
System.out.println("c");
c1++;
synchronized (xx1) {
xx1.notify();
}
try {
synchronized (xx3) {
xx3.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
c.setDaemon(true);
c.setName("ccc");
a.start();
b.start();
c.start();

synchronized (xx1) {
xx1.notify();
}

try {
Thread.sleep(100L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

}
mawerss1
2021-01-25 13:06:56 +08:00
public class Volatile implements Runnable{


private volatile int state = 0;

public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 3; i++) {
Thread thread = new Thread(new Volatile());
thread.start();
thread.join();
}
}

@Override
public void run() {
int count = 0;
while (true) {
if (count >= 100) {
break;
}
if (state == 0) {
System.out.println("a");
state = 1;
}
if (state == 1) {
System.out.println("b");
state = 2;
}
if (state == 2) {
System.out.println("c");
state = 0;
}
count++;
}
}
}
chenshun00
2021-01-25 13:12:25 +08:00
@mawerss1 好像偏题了
mytudan
2021-01-25 13:26:22 +08:00
class Abc {
private int n;
// 标志位,控制执行顺序,0 执行 a,1 执行 b 2 执行 c
private volatile int type;
// 锁标志
private final Object object;

public Abc(int n) {
this.n = n;
object = new Object();
type = 0;
}

public void a(Runnable a) throws InterruptedException {
for (int i = 0; i < n; i++) {
synchronized (object) {
while (!(type == 0)) {
object.wait();
}
a.run();
type = 1;
object.notifyAll();
}
}
}

public void b(Runnable b) throws InterruptedException {
for (int i = 0; i < n; i++) {
synchronized (object) {
while (!(type == 1)) {
object.wait();
}
b.run();
type = 2;
object.notifyAll();
}
}
}

public void c(Runnable c) throws InterruptedException {
for (int i = 0; i < n; i++) {
synchronized (object) {
while (!(type == 2)) {
object.wait();
}
c.run();
type = 0;
object.notifyAll();
}
}
}

}
mawerss1
2021-01-25 13:34:29 +08:00
@chenshun00 哈哈 全错了
chendy
2021-01-25 13:35:06 +08:00
生产者-消费者模型
a 生产 b 消费,b 生产 c 消费,c 生产 a 消费
leafre
2021-01-25 13:41:17 +08:00
ReentrantLock
hitmanx
2021-01-25 13:46:59 +08:00
把它看成三个独立的生产者消费者,用独立的 sync objects
woshiaha
2021-01-25 13:49:04 +08:00
老题了 用一个原子数当锁 每次有输出原子数都加一 抢到锁才可以输出
a 线程只在原子数%3 为 0 时输出
b 线程只在原子数%3 为 1 时输出
c 线程只在原子数%3 为 2 时输出
mytudan
2021-01-25 13:49:26 +08:00
我上面那个是照着 leetcode 上的题改的
mawerss1
2021-01-25 13:51:31 +08:00
@chenshun00 state 变量改成 static,join 方法删掉,改成用 CountDownLatch
yazinnnn
2021-01-25 13:56:11 +08:00
有个问题,这个多线程有什么意义?
Vendettar
2021-01-25 14:09:30 +08:00
```java
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock(true);
for (int i = 0; i < 3; i++) {
int order = i;
new Thread(()->{
for (int j = 0; j < 100; j++) {
lock.lock();
System.out.println(Thread.currentThread().getName() + ":" + (char)('a'+order));
lock.unlock();
}
}, "Thread-" + i).start();
}
}
```
Vendettar
2021-01-25 14:10:16 +08:00
直接一个公平锁 new ReentrantLock(true)按顺序来就可以
Takamine
2021-01-25 14:13:50 +08:00
刚撸的一个,应该算是比较传统的解法吧。
https://paste.ubuntu.com/p/zbDMK6qJQm/
micean
2021-01-25 14:14:46 +08:00
每个线程调用这个类就行了
class ABCPrinter{
int[] arr = new int[]{0, 0, 0};
int i = 0;

public synchronized void addChar(char ch){
arr[(int)(ch - 'a')]++;
print();
}

void print(){
while(arr[i] > 0){

打印((char)(arr[i] + 'a'));
arr[i]--;
i = (i + 1)%3

}
}

}
ocean1477
2021-01-25 14:14:54 +08:00
@Vendettar 直接不对。
Rorysky
2021-01-25 14:19:28 +08:00
synchronized 一把梭
kingwrcy
2021-01-25 14:19:41 +08:00
测试没毛病,其实就是 `synchronized ,wait , notify`几个函数

@yazinnnn 这题一毛钱意义都没有,实际业务中没写过这样的逻辑,主要是考察对多线程的熟悉程度吧.

public class TestMain {


private static class MyThread extends Thread{

private final int flag;
private final String str;
private final Object lock;
private final AtomicInteger counter;

public MyThread(int flag, String str,Object lock,AtomicInteger counter) {
this.flag = flag;
this.str = str;
this.lock = lock;
this.counter = counter;
}

@Override
public void run() {
synchronized (lock) {
while (counter.get() < 300) {
if (counter.get() % 3 == flag) {
System.out.print(str);
if (Objects.equals(str,"c")){
System.out.println();
}
counter.incrementAndGet();
lock.notifyAll();
} else {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}


public static void main(String[] args) {
AtomicInteger counter = new AtomicInteger(0);
Object lock = new Object();

MyThread threadA = new MyThread(0,"a",lock,counter);
MyThread threadB = new MyThread(1,"b",lock,counter);
MyThread threadC = new MyThread(2,"c",lock,counter);

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

try {
threadA.join();
threadB.join();
threadC.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}


}

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/748114

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX