有3个线程ABC。按照ABC来运行(A线程输出A,B线程输出B,C线程输出C,以此类推,循环输出)。

面试题Category: Java有3个线程ABC。按照ABC来运行(A线程输出A,B线程输出B,C线程输出C,以此类推,循环输出)。
魔尼尼 Staff asked 2 years ago

有3个线程ABC。按照ABC来运行(A线程输出A,B线程输出B,C线程输出C,以此类推,循环输出)。就是线程之间的协作。请问咋做呢?这种情况是只用一个锁来实现可以吗?

FavoriteLoading添加本文到我的收藏
Iron Staff replied 10 months ago

我设置了三把锁,每个线程初始化需要前、后两把锁,线程执行需要等前一个线程唤醒,然后执行,然后唤醒下一个线程。
public class Test2 {
class Worker implements Runnable {
private String id;
Object pre;
Object after;

public Worker(String id, Object pre, Object after) {
this.id = id;
this.pre = pre;
this.after = after;
}

@Override
public void run() {
while (true) {
try {
synchronized (pre) {
pre.wait();
}
System.out.println(id);
synchronized (after) {
after.notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}

}
}
}

public void fun() throws InterruptedException {
Object lockA_B = new Object();
Object lockB_C = new Object();
Object lockC_A = new Object();

new Thread(new Worker(“A”, lockC_A, lockA_B)).start();
Thread.sleep(100);
new Thread(new Worker(“B”, lockA_B, lockB_C)).start();
Thread.sleep(100);
new Thread(new Worker(“C”, lockB_C, lockC_A)).start();
Thread.sleep(100);
synchronized (lockC_A) {
lockC_A.notify();
}
}

public static void main(String[] args) throws InterruptedException {
new Test2().fun();
}
}

但是程序会按照顺序执行N次后就会阻塞,不知道问题在那

Iron Staff replied 10 months ago

wait和notify存在信号丢失问题,使用可重用闭锁,Semaphore就ok了
class Worker implements Runnable {
private String id;
Semaphore pre;
Semaphore after;

public Worker(String id, Semaphore pre, Semaphore after) {
this.id = id;
this.pre = pre;
this.after = after;
}

@Override
public void run() {
while (true) {
try {
pre.acquire();
System.out.println(id);
after.release();
} catch (InterruptedException e) {
e.printStackTrace();
}

}
}
}

public void fun() throws InterruptedException {
Semaphore semaphoreA_B = new Semaphore(1);
Semaphore semaphoreB_C = new Semaphore(1);
Semaphore semaphoreC_A = new Semaphore(1);
semaphoreB_C.acquire();
semaphoreA_B.acquire();
new Thread(new Worker(“A”, semaphoreC_A, semaphoreA_B)).start();
Thread.sleep(100);
new Thread(new Worker(“B”, semaphoreA_B, semaphoreB_C)).start();
Thread.sleep(100);
new Thread(new Worker(“C”, semaphoreB_C, semaphoreC_A)).start();
Thread.sleep(100);

}

public static void main(String[] args) throws InterruptedException {
new Test3().fun();
}

20 Answers
Best Answer
fleese Staff answered 2 years ago

用 Reentrantlock,用它的newCondition() 方法创建3个condition,按顺序调用 condition 的await和signal 方法就可以了,就不贴代码了,具体看Reentrantlock 和Condition 讲解。

FavoriteLoading添加本文到我的收藏
wangbingchen Staff answered 2 years ago

public static void main(String[] args) throws InterruptedException {
while(true){
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(“A”);
}
});
thread1.start();
thread1.join();

Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(“B”);
}
});
thread2.start();
thread2.join();

Thread thread3 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(“C”);
}
});
thread3.start();
thread3.join();
}
}

FavoriteLoading添加本文到我的收藏
zenfery Staff replied 5 months ago

你这个回答没有任何意义吧,跟 连接打印三个 sysout 没有啥区别呀。

zenfery Staff replied 5 months ago

题意应该是同时启动三个线程,都可以成功按规则打印。

Halis Staff answered 2 years ago
import java.util.HashMap;
import java.util.Map;

/**
* 有3个线程ABC。按照ABC来运行(A线程输出A,B线程输出B,C线程输出C,以此类推,循环输出)
*
* @author zagain
*
*/
public class ThreadTest1 {
private static final String A = "A";
private static final String B = "B";
private static final String C = "C";
private static final String _N = "\n";
private static final Map<String, String> TRANS = new HashMap<String, String>();
static {
TRANS.put(A, B);
TRANS.put(B, C);
TRANS.put(C, _N);
TRANS.put(_N, A);
}

private static volatile String currentInfo = A;

private static String nextInfo(String info) {
return TRANS.get(info);
}

public static void main(String[] args) {
new Thread(new PrintTask(A)).start();
new Thread(new PrintTask(B)).start();
new Thread(new PrintTask(C)).start();
//增加一个打印回车的线程,这样的话打印效果更好
new Thread(new PrintTask(_N)).start();
}

private static class PrintTask implements Runnable {
private final String info;

public PrintTask(String info) {
this.info = info;
}

@Override
public void run() {
for (;;) {
if (currentInfo == info) {// 这里用了双重检查,可以稍微提升性能
synchronized (currentInfo) {
if (currentInfo == info) {
System.out.print(info);
currentInfo = nextInfo(info);
}
}
}
}
}
}
}
FavoriteLoading添加本文到我的收藏
zhouyibing Staff answered 2 years ago

利用Atomic原子操作,实现顺序控制
@Test
public void test2() throws InterruptedException{
Thread a = new Thread(new PrintRunnable2(“A”,3,2));
Thread b = new Thread(new PrintRunnable2(“B”,2,1));
Thread c = new Thread(new PrintRunnable2(“C”,1,3));
a.start();
b.start();
c.start();
a.join();
b.join();
c.join();
}

static class PrintRunnable2 implements Runnable{
private String str;
private static AtomicInteger runFlag = new AtomicInteger(3);
private int mySequence;
private int next;

private PrintRunnable2(String str,int mySequence,int next) {
this.str = str;
this.mySequence = mySequence;
this.next=next;
}
@Override
public void run() {
while(true){
if(runFlag .get()== mySequence)
print();
}
}

public void print(){
System.out.print(str);
if(next>mySequence)
System.out.println();

//cas设置下一个执行序号
runFlag.compareAndSet(mySequence, next);
}
}

FavoriteLoading添加本文到我的收藏
1 2 3 5 Next »

return top