新作

时间:2024-07-14 13:42:24

控制多线程输出

  • 线程一,循环输出的1,线程二,循环输出2,线程三,循环输出3,写一个程序,控制这三个线程循环输出1,2,3,1,2,3,…
  • 这个欠缺的知识有点多,一时间不知道怎么弄,这里先补充一下
Java实现线程——不使用锁实现
  • 实现runnable接口的具体类
    • 重写runnable方法,然后在一个thread对象中传入对应的新实例,创建对应线程,然后进行运行
 public static void main(String[] args) {
        Thread t1 = new Thread(new ThreadTest(1));
        Thread t2 = new Thread(new ThreadTest(2));
        Thread t3 = new Thread(new ThreadTest(3));
        t1.start();
        t2.start();
        t3.start();
    }

    static class ThreadTest implements Runnable{

        int num = 0;

        ThreadTest(int val){
            num = val;
        }

        // define recursive function
        private void printNum() throws InterruptedException {
            while(true){
                System.out.print(num);
               Thread.sleep(100);
            }
        }

        @Override
        public void run() {
            try {
                printNum();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

下述是直接实现的效果,并不是完全的123顺序,所以这个方法并不合理!
在这里插入图片描述

版本一,通过全局变量实现控制输出的123

  • 这里虽然有多个线程,但是他们都是Main的内部类,以及内部实例,是共享一个静态变量的current,所以通过current进行设置即可!
public class Main {
    private static int current = 1;
    public static void main(String[] args) {
        Thread t1 = new Thread(new ThreadTest(1));
        Thread t2 = new Thread(new ThreadTest(2));
        Thread t3 = new Thread(new ThreadTest(3));
        t1.start();
        t2.start();
        t3.start();
    }
    static class ThreadTest implements Runnable{

        int num = 0;

        ThreadTest(int val){
            num = val;
        }

        // define recursive function
        private void printNum() throws InterruptedException {
            while(true){
                if (current == num){
                    System.out.print(num);
                    current ++;
                }
                if(current == 4)    current = 1;
               Thread.sleep(100);
            }
        }

        @Override
        public void run() {
            try {
                printNum();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

问题

  • 如果不使用对应锁进行控制,三个线程同时在输出前阻塞,然后输出顺序就没有办法控制了!仅仅是在这个简单程序出问题的概率比较低,如果复杂程序出问题的概率就高了!
使用synchronized关键实现——使用锁实现

synchronized关键字介绍

  • 修饰函数,多个线程只能互斥访问这个函数
  • 修饰代码块,多个线程只能访问特定的代码块(需要使用对象锁)

不使用synchronized实现方法
在这里插入图片描述
使用synchronized方法效果

  • 下文使用了synchronized方法之后的效果
public class Main {
    private static int current = 1;
    private static final Object lock = new Object();

    public static void main(String[] args) {
        Thread t1 = new Thread(new ThreadTest(1));
        Thread t2 = new Thread(new ThreadTest(2));
        Thread t3 = new Thread(new ThreadTest(3));
        t1.start();
        t2.start();
        t3.start();
    }

    static class ThreadTest implements Runnable{

        int num = 0;

        ThreadTest(int val){
            num = val;
        }

        // define recursive function
        private void printNum() throws InterruptedException {
            synchronized (lock){
                while(true){
                    current ++;
                    System.out.println(current);

                    Thread.sleep(100);
                }
            }

        }

        @Override
        public void run() {
            try {
                printNum();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

在这里插入图片描述

使用synchronized、wait和notify关键字实现

具体实现思路

  • 使用state来表示当前应该的打印那个字母,
  • 每一个线程打印字母之后,就要更新state并且唤醒正在等待的线程
public class Main {
    private static int current = 1;
    private static final Object lock = new Object();

    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable(){
            @Override
            public void run(){
                for(int i = 0;i < 100;i ++){
                    synchronized(lock){
                        // judge whether th current thread should print the num
                        try {
                            // if the current thread should not print num ,wait until the current changed
                            while (current % 3 != 1) {
                                lock.wait();
                            }
                            System.out.println(1);
                            current ++;
                            lock.notifyAll();
                        }catch(InterruptedException e){
                            e.printStackTrace();
                        }
                    }
                }
            }
        });


        Thread t2 = new Thread(new Runnable(){
            @Override
            public void run() {
                // traverse 100 times
                for(int i = 0;i < 100;i ++){
                    synchronized(lock){
                        try{
                            while(current % 3 != 2){
                                lock.wait();
                            }
                            System.out.println(2);
                            current ++;
                            lock.notifyAll();
                        }catch(InterruptedException e){
                            e.printStackTrace();
                        }
                    }
                }
            }
        });

        Thread t3 = new Thread(new Runnable(){
            @Override
            public void run(){
                for(int i = 0;i < 100;i ++){
                    synchronized(lock){
                        try{
                            while(current % 3 != 0) {
                                lock.wait();
                            }
                            System.out.println(3);
                            current ++;
                            lock.notifyAll();
                        }catch(InterruptedException e){
                            e.printStackTrace();
                        }
                    }
                }
            }
        });

        t1.start();
        t2.start();
        t3.start();
    }


}

这里有几个东西还是需要记住的

  • 重写的是Overirde,第一个字母是大写
  • notify和wait是会出现interruptedException异常
  • 打印输出异常信息是e.printStackTrace()