念两句诗

线程池相关

2024-08-23 浏览 面试必备 1293字 7 min read

交替打印数字

利用volatile同步

public class VolatilePrint {
    // 全局变量i,用于计数
    private static int i = 1;
    // 是否是奇数的标志,用volatile保证可见性
    private static volatile boolean isOdd = true;

    public static void main(String[] args) {
        // 线程A,负责打印奇数
        new Thread(() -> {
            while (i <= 100) {
                if (isOdd) {
                    // 打印奇数
                    System.out.println(Thread.currentThread().getName() + ":" + i++);
                    // 打印完奇数后,将标志设为false
                    isOdd = false;
                }
            }
        }, "Thread-A").start();

        // 线程B,负责打印偶数
        new Thread(() -> {
            while (i <= 100) {
                if (!isOdd) {
                    // 打印偶数
                    System.out.println(Thread.currentThread().getName() + ":" + i++);
                    // 打印完偶数后,将标志设为true
                    isOdd = true;
                }
            }
        }, "Thread-B").start();
    }
}

利用wait()/notify()同步

public class WaitNotify {
    // 全局变量i,用于计数
    public static int i = 1;
    // 锁对象,用于线程同步
    public static final Object lock = new Object();

    public static void main(String[] args) {
        // 线程A,负责打印奇数
        new Thread(() -> {
            synchronized (lock) {
                while (i <= 100) {
                    if (i % 2 == 1) {
                        // 打印奇数
                        System.out.println(Thread.currentThread().getName() + ":" + i++);
                        // 唤醒其他线程
                        lock.notify();
                    } else {
                        try {
                            // 当前线程等待,释放锁
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }, "Thread-A").start();

        // 线程B,负责打印偶数
        new Thread(() -> {
            synchronized (lock) {
                while (i <= 100) {
                    if (i % 2 == 0) {
                        // 打印偶数
                        System.out.println(Thread.currentThread().getName() + ":" + i++);
                        // 唤醒其他线程
                        lock.notify();
                    } else {
                        try {
                            // 当前线程等待,释放锁
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }, "Thread-B").start();
    }
}

使用Semaphore信号量

import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    // 全局变量i,用于计数
    private static int i = 1;
    // 奇数信号量,初始许可数为1
    private static Semaphore semaphoreOdd = new Semaphore(1);
    // 偶数信号量,初始许可数为0
    private static Semaphore semaphoreEven = new Semaphore(0);

    public static void main(String[] args) {
        // 线程A,负责打印奇数
        new Thread(() -> {
            while (i <= 100) {
                try {
                    // 获取奇数信号量,获取后许可数变为0
                    semaphoreOdd.acquire();
                    // 打印奇数
                    System.out.println(Thread.currentThread().getName() + ":" + i++);
                    // 释放偶数信号量,许可数加1
                    semaphoreEven.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "Thread-A").start();

        // 线程B,负责打印偶数
        new Thread(() -> {
            while (i <= 100) {
                try {
                    // 获取偶数信号量,获取后许可数变为0
                    semaphoreEven.acquire();
                    // 打印偶数
                    System.out.println(Thread.currentThread().getName() + ":" + i++);
                    // 释放奇数信号量,许可数加1
                    semaphoreOdd.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "Thread-B").start();
    }
}

使用Condition和Lock

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ConditionExample {
    // 全局变量i,用于计数
    private static int i = 1;
    // 可重入锁
    private static final Lock lock = new ReentrantLock();
    // 奇数条件变量
    private static final Condition conditionOdd = lock.newCondition();
    // 偶数条件变量
    private static final Condition conditionEven = lock.newCondition();

    public static void main(String[] args) {
        // 线程A,负责打印奇数
        new Thread(() -> {
            lock.lock();  // 加锁
            try {
                while (i <= 100) {
                    if (i % 2 == 1) {
                        // 打印奇数
                        System.out.println(Thread.currentThread().getName() + ": " + i++);
                        // 唤醒偶数条件变量等待的线程
                        conditionEven.signal();
                    } else {
                        // 当前线程等待在奇数条件变量上,释放锁
                        conditionOdd.await();
                    }
                }
                // 结束时,唤醒对方线程,防止阻塞
                conditionEven.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();  // 释放锁
            }
        }, "Thread-A").start();

        // 线程B,负责打印偶数
        new Thread(() -> {
            lock.lock();  // 加锁
            try {
                while (i <= 100) {
                    if (i % 2 == 0) {
                        // 打印偶数
                        System.out.println(Thread.currentThread().getName() + ": " + i++);
                        // 唤醒奇数条件变量等待的线程
                        conditionOdd.signal();
                    } else {
                        // 当前线程等待在偶数条件变量上,释放锁
                        conditionEven.await();
                    }
                }
                // 结束时,唤醒对方线程,防止阻塞
                conditionOdd.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();  // 释放锁
            }
        }, "Thread-B").start();
    }
}

使用AQS

import java.util.concurrent.locks.AbstractQueuedSynchronizer;

public class AQSSyncExample {
    // 全局变量i,用于计数
    private static int i = 1;

    // 自定义AQS类,负责奇偶数线程的同步
    private static class MyAQS extends AbstractQueuedSynchronizer {
        public MyAQS() {
            // 初始状态为1,表示奇数线程先执行
            setState(1);
        }

        // 打印奇数
        public void printOdd(Runnable printOdd) {
            acquire(1);  // 获取状态为1的许可
            printOdd.run();  // 执行打印操作
            release(0);  // 释放状态为0的许可
        }

        // 打印偶数
        public void printEven(Runnable printEven) {
            acquire(0);  // 获取状态为0的许可
            printEven.run();  // 执行打印操作
            release(1);  // 释放状态为1的许可
        }

        @Override
        protected boolean tryAcquire(int arg) {
            return getState() == arg;  // 获取许可时,判断当前状态是否匹配
        }

        @Override
        protected boolean tryRelease(int arg) {
            setState(arg);  // 释放许可时,设置新的状态
            return true;
        }
    }

    public static void main(String[] args) {
        MyAQS aqs = new MyAQS();

        // 线程A,负责打印奇数
        new Thread(() -> {
            while (i <= 100) {
                aqs.printOdd(() -> {
                    // 打印奇数
                    System.out.println(Thread.currentThread().getName() + ": " + i++);
                });
            }
        }, "Thread-A").start();

        // 线程B,负责打印偶数
        new Thread(() -> {
            while (i <= 100) {
                aqs.printEven(() -> {
                    // 打印偶数
                    System.out.println(Thread.currentThread().getName() + ": " + i++);
                });
            }
        }, "Thread-B").start();
    }
}

使用LockSupport

import java.util.concurrent.locks.LockSupport;

public class LockSupportExample {
    // 全局变量i,用于计数
    private static int i = 1;
    // 线程引用,用于唤醒对方线程
    private static Thread threadA, threadB;

    public static void main(String[] args) {
        // 线程A,负责打印奇数
        threadA = new Thread(() -> {
            while (i <= 100) {
                if (i % 2 == 1) {
                    // 打印奇数
                    System.out.println(Thread.currentThread().getName() + ": " + i++);
                    // 唤醒线程B
                    LockSupport.unpark(threadB);
                    // 当前线程等待
                    LockSupport.park();
                }
            }
            // 结束时,防止对方线程被永远阻塞
            LockSupport.unpark(threadB);
        }, "Thread-A");

        // 线程B,负责打印偶数
        threadB = new Thread(() -> {
            while (i <= 100) {
                // 当前线程等待
                LockSupport.park();
                if (i % 2 == 0) {
                    // 打印偶数
                    System.out.println(Thread.currentThread().getName() + ": " + i++);
                    // 唤醒线程A
                    LockSupport.unpark(threadA);
                }
            }
        }, "Thread-B");

        // 启动线程
        threadA.start();
        threadB.start();
    }
}
EOF