CONTENT
1. 实现一个死锁 快手一面8.11
思路:两个线程,两个Object A 和 B,线程一先获得 A 再获得 B,线程二先获得 B 再获得 A。为防止效果不明显,可以在 线程一获得 A 之后 sleep 一段时间,线程二获得 B 之后 sleep 一段时间。
实现一
写在一个 run()
方法里,用线程名判断先获取 A 还是 B。
public class TwoThreadDeadLock {
public static void main(String[] args) {
DeadLock deadLock = new DeadLock();
new Thread(deadLock, "1").start();
new Thread(deadLock, "2").start();
}
}
class DeadLock implements Runnable {
private final Object A = new Object();
private final Object B = new Object();
@Override
public void run() {
String currentThreadName = Thread.currentThread().getName();
if (currentThreadName.equals("1")) {
synchronized (A) {
System.out.println(currentThreadName + " get A");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (B) {
System.out.println(currentThreadName + " get B");
}
}
} else {
synchronized (B) {
System.out.println(currentThreadName + " get B");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (A) {
System.out.println(currentThreadName + " get A");
}
}
}
}
}
实现二(提取相同逻辑更简洁)
把获取锁的代码写进一个方法里,因为逻辑都是一样,先获取一个锁再获取另一个。
public class Main {
public static void main(String[] args) {
Object A = new Object();
Object B = new Object();
new Thread(() -> {
task(A, B);
}).start();
new Thread(() -> {
task(B, A);
}).start();
}
static void task(Object first, Object second) {
String currentThreadName = Thread.currentThread().getName();
synchronized (first) {
System.out.println(currentThreadName + " get " + first);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (second) {
System.out.println(currentThreadName + " get " + second);
}
}
}
}
2. 两个线程交替打印 0-100
思路:把打印部分的代码用 synchronized 包起来,打印之后先 notifyAll() 唤醒另一个线程,然后 wait() 自己并释放锁,让另一个线程打印下一个数字,如此往复,直到打印到 100,notifyAll() 另一个线程结束循环。
public class TwoThread0to100 {
public static void main(String[] args) {
Print p = new Print();
new Thread(p).start();
new Thread(p).start();
}
}
class Print implements Runnable {
private int number = 0;
@Override
public void run() {
while (true) {
synchronized (this) {
if (number >= 100) {
notifyAll();
break;
}
System.out.println(Thread.currentThread().getName() + " : " + (++number));
notifyAll();
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
3. 三个线程交替打印,线程0打印零,线程1打印奇数,线程0打印0,线程2打印偶数 01020304 … 拼多多一面
思路:判断是否轮到当前线程打印,轮到就打印并 notifyAll() 其他线程尝试打印下一个数字;没轮到就 wait(),没轮到有四种情况:
总的来说分为两种情形,索引是奇数时线程0打印零,索引是偶数时那么线程1打印奇数或者线程2打印偶数。
- 因此如果当前进来的是线程0并且当前索引是偶数,那当前没轮到线程0打印,wait()
- 如果不是线程0,是线程1或线程2,并且当前索引是奇数,那当前轮到线程0打印,wait()
对于索引是偶数的情况,还要区分当前是打印奇数还是偶数,如果索引除2之后结果是奇数,那当前该打印奇数,除2之后结果是偶数,那当前该打印偶数。
- 所以如果当前是线程1,并且当前索引除2不是奇数,wait()
- 如果当前是线程2,并且当前索引除2是奇数,wait()
public class TriThread {
public static void main(String[] args) {
Alternate alternate = new Alternate();
new Thread(alternate, "0").start();
new Thread(alternate, "1").start();
new Thread(alternate, "2").start();
}
}
class Alternate implements Runnable {
private int number = 1;
@Override
public void run() {
while (number <= 200) {
synchronized(this) {
String currentThreadName = Thread.currentThread().getName();
if (currentThreadName.equals("0") && (number&1)!=1 ||
!currentThreadName.equals("0") && (number&1)==1 ||
currentThreadName.equals("1") && ((number/2)&1)!=1 ||
currentThreadName.equals("2") && ((number/2)&1)==1) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
System.out.println(currentThreadName + " : " + (currentThreadName.equals("0") ? 0 : number/2));
number++;
notifyAll();
}
}
}
}
}
4. 四个线程交替打印ABCD,打印10次 美团一面8.17
public class Main {
public static void main(String[] args) {
new Thread(new SwapPrint(0)).start();
new Thread(new SwapPrint(1)).start();
new Thread(new SwapPrint(2)).start();
new Thread(new SwapPrint(3)).start();
}
}
class SwapPrint implements Runnable{
private static final Object lock = new Object();
private static int count = 0;
private final int no;
public SwapPrint(int no){
this.no = no;
}
@Override
public void run() {
while (true) {
synchronized (lock) {
if (count >= 40) {
break;
}
if (count % 4 == this.no) {
System.out.println("count: " + (count+1) + " thread" + (this.no+1) + "--->" + (char)('A'+(count%4)));
count++;
} else {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lock.notifyAll();
}
}
}
}