【面试题】关于线程交替的面试题
线程交替打印的题经常出现,总结一下:
一、两个线程交替打印0~100的奇偶数
/*
* 1.wait和notify都是Object类的方法。
* 2.wait和notify必须要在synchronized代码块中执行,否则会抛异常。
*/
public class WaitNotifyPrint {
private static int count = 0;
//两个线程竞争该对象锁
private static final Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
new Thread(new TurningRunner(), "偶数").start();
new Thread(new TurningRunner(), "奇数").start();
}
//1. 拿到锁直接就打印。
//2. 打印完,唤醒其他线程,自己就休眠。
static class TurningRunner implements Runnable {
@Override
public void run() {
while (count <= 100) {
synchronized (lock) {
//拿到锁就打印
System.out.println(Thread.currentThread().getName() + ":" + count++);
//打印完,唤醒其他线程
lock.notify();
//如果任务还没结束,就调用wait()让出当前的锁
if (count <= 100) {
try {
//自己休眠
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
}
二、生产者消费者
/*
* 用EventStorage模拟仓库,Producer代表生产者,Consumer代表消费者,
* 生产者和消费者共同对仓库进行协作。
*/
public class ProducerConsumerModel {
public static void main(String[] args) {
//初始化仓库
EventStorage eventStorage = new EventStorage();
//用仓库初始化生产者
Producer producer = new Producer(eventStorage);
//用仓库初始化消费者
Consumer consumer = new Consumer(eventStorage);
//启动生产者和消费者
new Thread(producer).start();
new Thread(consumer).start();
}
}
class Producer implements Runnable {
private EventStorage storage;
public Producer(
EventStorage storage) {
this.storage = storage;
}
@Override
public void run() {
//生产者往仓库中生产100个对象(此时消费者也在消费)
for (int i = 0; i < 100; i++) {
storage.put();
}
}
}
class Consumer implements Runnable {
private EventStorage storage;
public Consumer(
EventStorage storage) {
this.storage = storage;
}
@Override
public void run() {
//消费者循环消费仓库中的对象(此时生产者也在生产)
for (int i = 0; i < 100; i++) {
storage.take();
}
}
}
class EventStorage {
private int maxSize;
//用Date来模拟对象
private LinkedList<Date> storage;
//注意看构造方法定义仓库大小为10,并且用LinkedList来存储对象
public EventStorage() {
maxSize = 10;
storage = new LinkedList<>();
}
public synchronized void put() {
//仓库满了就休眠
while (storage.size() == maxSize) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//仓库没满就添加并通知消费者
storage.add(new Date());
System.out.println("仓库里有了" + storage.size() + "个产品。");
notify();
}
public synchronized void take() {
//仓库空了就休眠
while (storage.size() == 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//没空就取数据,poll方法代表检索并删除并通知生产者
System.out.println("拿到了" + storage.poll() + ",现在仓库还剩下" + storage.size());
notify();
}
}
三、交替打印ABC
方法一、synchronized
public class ABC {
public static class ThreadPrinter implements Runnable {
private String name;
private Object prev;
private Object self;
private ThreadPrinter(String name,Object prev,Object self){
this.name=name;
this.prev=prev;
this.self=self;
}
@Override
public void run() {
while (true){
synchronized (prev){
synchronized (self){
System.out.println(name);
self.notifyAll();
}
try{
prev.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Object a = new Object();
Object b = new Object();
Object c = new Object();
ThreadPrinter pa=new ThreadPrinter("A",c,a);
ThreadPrinter pb=new ThreadPrinter("B",a,b);
ThreadPrinter pc=new ThreadPrinter("C",b,c);
//保证ABC顺序执行
new Thread(pa).start();
Thread.sleep(10);
new Thread(pb).start();
Thread.sleep(10);
new Thread(pc).start();
Thread.sleep(10);
}
}
}
方法二、ReentrantLock
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ABC2 {
private static Lock lock= new ReentrantLock();
private static int state=0;
static class ThreadA extends Thread{
@Override
public void run() {
while(true) {
try {
lock.lock();
while (state % 3 == 0) {
System.out.println("A");
state++;
}
} finally {
lock.unlock();
}
}
}
}
static class ThreadB extends Thread{
@Override
public void run() {
while(true) {
try {
lock.lock();
while (state % 3 == 1) {
System.out.println("B");
state++;
}
} finally {
lock.unlock();
}
}
}
}
static class ThreadC extends Thread{
@Override
public void run() {
while(true) {
try {
lock.lock();
while (state % 3 == 2) {
System.out.println("C");
state++;
}
} finally {
lock.unlock();
}
}
}
}
public static void main(String[] args) {
new ThreadA().start();
new ThreadB().start();
new ThreadC().start();
}
}
方法三、信号量
public class ABC3 {
private static Semaphore A =new Semaphore(1);
private static Semaphore B =new Semaphore(0);
private static Semaphore C =new Semaphore(0);
static class ThreadA extends Thread{
@Override
public void run() {
try {
while(true){
A.acquire();
System.out.println("A");
B.release();
}
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
static class ThreadB extends Thread{
@Override
public void run() {
try {
while(true){
B.acquire();
System.out.println("B");
C.release();
}
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
static class ThreadC extends Thread{
@Override
public void run() {
try {
while(true){
C.acquire();
System.out.println("C");
A.release();
}
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
new ThreadA().start();
new ThreadB().start();
new ThreadC().start();
}
}