两个线程交替执行,线程1执行10次线程2执行5次,交替15次

**

两个线程交替执行

**
最近看到一个面试题,两个线程交替执行10次,线程1输出10次,线程2输出5次,反复交替15次。

方法一

一个主线程一个子线程,子线程运行在主线程内部,交替执行分别输出10次和5次,交替15次

package com.example.xssDemo.xss.util;

/**
 * @author liaoc
 */
public class ThreadPractice {
    public static void main(String[] args) {
        Do ado = new Do();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <= 15; i++) {
                    ado.sub(i);
                }
            }
        }).start();

        for (int j = 1; j <= 15; j++) {
            ado.main(j);
            System.out.println("===========第" + j + "轮完成===================");
        }
        System.out.println("===================================");
    }

    static class Do {
        private boolean isSun = true;
        //isSun为true执行该方法
        public synchronized void sub(int i) {
            if (!isSun) {
                try {
                    //wait()使当前线程阻塞,前提是 必须先获得锁,一般配合synchronized 关键字使用
                    //当线程执行wait()方法时候,会释放当前的锁,然后让出CPU,进入等待状态
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            for (int j = 1; j <= 10; j++) {
                System.out.println("子线程:" + Thread.currentThread().getName() + "," +
                        i + "趟," + "第:" + j + "个");

            }
            isSun = false;
            /**
             * notify方法只唤醒一个等待(对象的)线程并使该线程开始执行。
             * 所以如果有多个线程等待一个对象,这个方法只会唤醒其中一个线程,
             * 选择哪个线程取决于操作系统对多线程管理的实现。
             * notifyAll 会唤醒所有等待(对象的)线程,尽管哪一个线程将会第一个处理取决于操作系统的实现。
             * 如果当前情况下有多个线程需要被唤醒,推荐使用notifyAll 方法
             */
            this.notify();
        }
        //isSun为false执行该方法
        public synchronized void main(int i) {
            if (isSun) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            for (int j = 1; j <= 5; j++) {
                System.out.println("主线程:" + Thread.currentThread().getName() + "," + i
                        + "趟," + j + "个");
            }
            isSun = true;
            this.notify();
        }
    }
}
方法二

两个并列的子线程,交替执行分别输出10次和5次,交替15次。

package com.example.xssDemo.xss.util;

/**
 * @author liaoc
 */
public class BrotherThread {
    public static void main(String[] args) {
        Dto dto = new Dto();
        /**
         * 两个并列线程交替执行,输出10次,供交替20次
         */
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <= 15; i++) {
                    dto.sub1(i);
                    System.out.println("我是:" + Thread.currentThread().getName() + "第" + i + "趟");
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int j = 1; j <= 15; j++) {
                    dto.sub2(j);
                    System.out.println("我是:" + Thread.currentThread().getName() + "第" + j + "趟");
                }
            }
        }).start();
    }

    static class Dto {
        private boolean isSun = true;

        //isSun为true执行
        public synchronized void sub1(int i) {
            if (!isSun) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            for (int j = 1; j < 10; j++) {
                System.out.println(Thread.currentThread().getName() + "的第:" + i + "趟的第" + j + "个");
            }
            isSun = false;
            this.notify();
        }

        //isSun为false执行
        public synchronized void sub2(int i) {
            if (isSun) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            for (int j = 1; j <= 5; j++) {
                System.out.println(Thread.currentThread().getName() + "的第:" + i + "趟的第" + j + "个");
            }
            isSun = true;
            this.notify();
        }
    }
}

顺便复习一下线程的常用关键字:
1.start()和run()

start()方法是是开启线程的方法,这个方法执行后,一个线程才真正的进入RUNNABLE状态。run()方法是线程中具体执行的业务活动,一般都要重写run()方法
2.stop()方法在结束线程时,会直接终止线程,并立即释放这个线程所持有的锁
3.interrupt()方法是一个实例方法,它通知目标线程中断,也就是设置中断标志位
4.sleep()方法是让当前线程休眠若干时间,它会抛出一个InterruptedException中断异常,sleep()方法不会释放任何对象的锁资源
5.wait()等待方法,是Object类中的方法,当一个对象实例上调用wait()方法后,当前线程就会在这个对象上等待。那么等待什么时候结束呢?线程一直等到其他线程调用了这个对象的notify()方法为止。这样实例对象就成了多个线程间的通信手段。wait()和notify()不能随便调用,它必须包含在对应的synchronize语句中,这俩方法,都需要首先获得目标对象的一个监听器,而wait()和notify()方法在执行后会释放这个监听器。wait()方法会释放目标对象的锁。
6. join()方法表示无限的等待,他会一直阻塞当前线程,只到目标线程执行完毕。join(long millis) 给出了一个最大等待时间,如果超过给定的时间目标线程还在执行,当前线程就不等了,继续往下执行。

7. yeild()方法是个静态方法,一旦执行,他会使当前线程让出CPU。让出CPU不代表当前线程不执行了,还会进行CPU资源的争夺。如果一个线程不重要或优先级比较低,可以调用这个方法,把资源给重要的线程去做。
8. volatile:
并发编程的三个重要特征:原子性、可见性、有序性

原子性:是指在一次或多次操作中,要么所有的操作全部都执行并不会受任何因素的干扰而中断,要么所有的操作都不执行。
可见性:当一个线程对共享变量修改后,其他线程可立即看到最新的值。
有序性:所谓有序性是指程序代码在执行过程中的先后顺序,由于java编译和运行期的优化,会使得代码的执行顺序未必是开发者编写代码的顺序

发布了67 篇原创文章 · 获赞 12 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/m0_37635053/article/details/104698022