两个线程交替打印0~100的奇偶数

用synchronized关键字实现

public class TestMain {

    //定义一个int变量
    private static volatile int number = 0;

    //定义一个对象锁
    private static final Object lock = new Object();

    public static void main(String[] args) throws InterruptedException {
        long startTime = System.currentTimeMillis();
        //偶数线程
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                //判断数值是否小于100,小于则进入同步块做判断输出和自增
                while (number < 100) {
                    synchronized (lock) {
                        //等价于number%2==0,用位运算效率更高
                        if ((number & 1) == 0) {
                            System.out.println(Thread.currentThread().getName() + ":" + number++);
                        }
                    }
                }
            }
        }, "偶数");

        //奇数线程
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                //判断数值是否小于100,小于则进入同步块做判断输出和自增
                while (number < 100) {
                    synchronized (lock) {
                        //等价于number%2==1,用位运算效率更高
                        if ((number & 1) == 1) {
                            System.out.println(Thread.currentThread().getName() + ":" + number++);
                        }
                    }
                }
            }
        }, "奇数");
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println("总耗时:" + (System.currentTimeMillis() - startTime) + "毫秒");
    }
}

运行结果如下:
两个线程交替打印0~100的奇偶数_第1张图片
两个线程交替打印0~100的奇偶数_第2张图片

可以发现两次运行的时间差大概都有2倍了,这是因为用synchronized关键字来实现,虽然结果是可以达到预期的,但是在多线程运行中,往往可能一个线程能多次得到运行机会,这样就会导致时间的浪费,所以我们虽然看到的是两个线程交替打印奇偶数,但很大的可能是其中一个线程都做了好几次同步块的逻辑,另一个线程才抢到运行的机会,所以效率快慢完全看运气。

使用wait/notify来实现

public class TestMain {

    //定义一个int变量
    private static volatile int number = 0;

    //定义一个对象锁
    private static final Object lock = new Object();

    static class NumberThread implements Runnable {
        @Override
        public void run() {
            //小于等于100则进入同步块
            while (number <= 100) {
                synchronized (lock) {
                    //输出当前值后加一
                    System.out.println(Thread.currentThread().getName() + ":" + number++);
                    //唤醒等待中的线程
                    lock.notify();
                    //这个判断很关键,要是不写,结果输出虽然是一样的,但是程序运行不会结束,因为有线程会陷入无限的等待,而没有其他线程可以来唤醒它
                    if (number <= 100) {
                        try {
                            //让出CPU资源,释放锁,让另一个线程运行,同时等待被另一个线程唤醒
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        long startTime = System.currentTimeMillis();
        NumberThread numberThread = new NumberThread();
        Thread thread1 = new Thread(numberThread, "偶数");
        Thread thread2 = new Thread(numberThread, "奇数");
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println("总耗时:" + (System.currentTimeMillis() - startTime) + "毫秒");
    }
}

运行结果如下:
两个线程交替打印0~100的奇偶数_第3张图片

一个线程输出完值后,如果还没有达到100,就会唤醒与之配合的另一个线程同时自己让出锁资源进入等待,等待唤醒,这样子就算真正的实现交替运行。

总结

实现需求方法有很多种,试着选择自己能力范围内的最优解。

你可能感兴趣的:(Java并发编程)