java中两个线程交替执行打印a-z,1-26的方式

先介绍一种synchronized方式的实现:

  提到交替打印,用到synchronized,不得不提到wait和notify,当前线程打印出当前数据之后,wait之前,需要通知其他,我即将wait,你可以继续运行了,好了,话不多说,直接上代码:

 1 public class T02_ReentrantLock2 {
 2     
 3     synchronized void s1() {
 4         String abc = "abcdefghijklmnopqrstuvwxyz";
 5         String[] a = abc.split("");
 6             for(String value : a) {
 7                 System.out.println(value);
 8                 this.notify();
 9                 try {
10                     this.wait();
11                     Thread.sleep(100);// 防止打印速度过快导致混乱
12                 } catch (InterruptedException e) {
13                     e.printStackTrace();
14                 }
15             }
16         
17     }
18     synchronized void n1() {
19         
20             for(int i = 1; i< 27; i++) {
21                 System.out.println(i);
22                 this.notify();
23                 try {
24                     this.wait();
25                     Thread.sleep(100);// 防止打印速度过快导致混乱
26                 } catch (InterruptedException e) {
27                     e.printStackTrace();
28                 }
29             }
30             
31     }
32     
33     public static void main(String[] args) {
34         T02_ReentrantLock2 rl = new T02_ReentrantLock2();
35         Thread t1 = new Thread(rl::s1);
36         Thread t2 = new Thread(rl::n1);
37         t1.start();
38         t2.start();
39     }
40 }

  其实实现很简单,最主要的点,就是什么时候wait,什么时候notify,正常情况下,他们是交替出现的,目的都是currentThread wait之前,唤起其他线程。

  接下来是第二种,也是稍微复杂点的方式,直接使用ReentrantLock,进一步使用Condition,Condition相当于一个容器,在一个Lock中New多少个Condition,就相当于创建了多少个等待队列,因此,通过一个lock,两个不同的线程,两个Condition,可以轻松实现以上需求,需要注意的是,每次lock后需要及时unlock。

public class T01_ReentrantLock1 {

    public static boolean isInteger(String str) {
        Pattern pattern = Pattern.compile("[0-9]*");
        return pattern.matcher(str).matches();
    }

    private static Lock lock = new ReentrantLock();
    private static List<String> a = new ArrayList<String>(
            Arrays.asList("a", "1", "b", "2", "c", "3", "d", "4", "e", "5", "f", "6", "g", "7", "h", "8", "i", "9", "j",
                    "10", "k", "11", "l", "12", "m", "13", "n", "14", "o", "15", "p", "16", "q", "17", "r", "18", "s",
                    "19", "t", "20", "u", "21", "v", "22", "w", "23", "x", "24", "y", "25", "z", "26"));
    private static volatile int i = 0;

    public static void main(String[] args) {

        Condition number = lock.newCondition();
        Condition abcString = lock.newCondition();
        new Thread(() -> {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
            while(i < a.size()){
                lock.lock();
                try {
                    if (isInteger(a.get(i)) ) {
                        abcString.await();
                    }
                    if(i < a.size()) {
                        System.out.println(Thread.currentThread() + " : " + a.get(i));
                        i++;
                        number.signal();
                    }
                    
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }

        }, "String").start();
        new Thread(() -> {
            try {
                Thread.sleep(100);
                while (i < a.size()) {
                    lock.lock();
                    // 必须带条件才会相互切换,且判断带条件必须是同一个对象
                    if (!isInteger(a.get(i))) {
                        number.await();
                    }
                    // 必须在打印之前判断下,是否另外一个线程i++后还小于数组,否则数组下表越界
                    if (i < a.size()) {
                        System.out.println(Thread.currentThread() + " : " + a.get(i));
                        i++;
                        abcString.signal();
                    }

                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }

        }
            , "num").start();
    }

}

第二种方式,个人感觉还存在优化的空间,欢迎大家一起进行讨论。