多线程面试题
两个线程一个打印奇数一个打印偶数
private int count = 0;
private final Object lock = new Object();
@Test
public void test() throws InterruptedException {
Thread even = new Thread(new TurningRunner(), "偶数");
even.start();
// 确保偶数线程线先获取到锁
Thread.sleep(1);
Thread odd = new Thread(new TurningRunner(), "奇数");
odd.start();
even.join();
odd.join();
}
class TurningRunner implements Runnable {
@Override
public void run() {
while (count <= 100) {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + ": " + count++);
lock.notifyAll();
try {
if (count <= 100) {
lock.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
N个线程顺序循环打印从0至100
通过N个线程顺序循环打印从0至100,如给定N=3。则输出: thread0: 0 thread1: 1 thread2: 2 thread0: 3 thread1: 4
这道题很考察多线程基础。主要在于N个线程循环打印。关键在于如何控制线程的执行顺序,即唤醒特定的线程。之前通过notify()唤醒一个,notifyAll()唤醒全部,但都无法选择特定的线程执行。那如何控制控制线程有序的打印呢?
这里可以用semaphore信号量实现。设置semaphore[]数组,每个线程持有本身的信号量以及上个线程的信号量。对于三个线程abc来说,他们的last信号量对应关系为:
a.last - > semaphores[2]
b.last - > semaphores[0]
c.last - > semaphores[1]
每个线程执行时,会抢占last信号量,如a抢占 semaphores[2],同时释放当前信号量semaphores[0],通知等待队列中的线程b,这时线程b才能抢占通过它的last信号量:semaphores[0],同时再释放semaphores[1],然后唤醒c线程。。依此循环执行。
int count = 0;
Thread[] threads;
Semaphore[] semaphores;
public void print(int len) throws Exception {
threads = new Thread[len];
semaphores = new Semaphore[len];
for (int i = 0; i < len; i++) {
semaphores[i] = new Semaphore(1);
if (i != len - 1) {
semaphores[i].acquire();
}
}
for (int i = 0; i < len; i++) {
Semaphore lastSemphore = i == 0 ? semaphores[len - 1] : semaphores[i - 1];
Semaphore cur = semaphores[i];
threads[i] = new orderThread(lastSemphore, cur, "线程" + i);
threads[i].start();
}
}
class orderThread extends Thread {
/**
* 每一个线程都保存上一个线程对应的信号量
*/
Semaphore last;
/**
* 保存当前线程的信号量
*/
Semaphore cur;
orderThread(Semaphore last, Semaphore cur, String threadName) {
super(threadName);
this.last = last;
this.cur = cur;
}
/**
* 争夺上个线程的信号量,同时释放当前线程的信号量。这样唤醒下一个线程去争夺当前线程的信号量。
*/
@Override
public void run() {
while (count <= 100) {
try {
last.acquire();
//需要判断,防止线程被唤醒的时候,此时已经超过了100
if (count <= 100) {
System.out.println(Thread.currentThread().getName() + " : " + count++);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
cur.release();
}
}
}
}
@Test
public void test() throws Exception {
print(3);
Thread.sleep(3000);
}
synchornized锁住的是什么
synchronized(obj) ,obj非static,锁的是实例对象,不是代码。当synchronized锁住一个对象后,别的线程如果也想拿到这个对象的锁,就必须等待这个线程执行完成释放锁,才能再次给对象加锁,这样才达到线程同步的目的。
synchronized(xx.class)锁的是class对象,全局性的,相当于锁住了代码块。
阻塞队列实现生产者消费者模型
//生产者
public static class Producer implements Runnable {
private final BlockingQueue<Integer> blockingQueue;
private volatile boolean flag;
private Random random;
public Producer(BlockingQueue<Integer> blockingQueue) {
this.blockingQueue = blockingQueue;
flag = false;
random = new Random();
}
public void run() {
while (!flag) {
int info = random.nextInt(100);
try {
blockingQueue.put(info);
System.out.println(Thread.currentThread().getName() + " produce " + info);
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void shutDown() {
flag = true;
}
}
//消费者
public static class Consumer implements Runnable {
private final BlockingQueue<Integer> blockingQueue;
private volatile boolean flag;
public Consumer(BlockingQueue<Integer> blockingQueue) {
this.blockingQueue = blockingQueue;
}
public void run() {
while (!flag) {
int info;
try {
info = blockingQueue.take();
System.out.println(Thread.currentThread().getName() + " consumer " + info);
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void shutDown() {
flag = true;
}
}
public static void main(String[] args) {
BlockingQueue<Integer> blockingQueue = new LinkedBlockingQueue<Integer>(10);
Producer producer = new Producer(blockingQueue);
Consumer consumer = new Consumer(blockingQueue);
//创建5个生产者,5个消费者
for (int i = 0; i < 10; i++) {
if (i < 5) {
new Thread(producer, "producer" + i).start();
} else {
new Thread(consumer, "consumer" + (i - 5)).start();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
producer.shutDown();
consumer.shutDown();
}
手写生产者消费者模型
Integer count = 0;
Object obj = new Object();
private void produce() {
while (true) {
synchronized (obj) {
while (count == 10) {
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count++;
System.out.println("生产后count = " + count);
obj.notifyAll();
}
}
}
private void consume() {
while (true) {
synchronized (obj) {
while (count <= 0) {
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count--;
System.out.println("消费后count = " + count);
obj.notifyAll();
}
}
}
@Test
public void test() throws InterruptedException {
Thread t1 = new Thread(()->produce());
Thread t2 = new Thread(()->consume());
t1.start();
t2.start();
t1.join();
t2.join();
}
Last updated
Was this helpful?