zoukankan      html  css  js  c++  java
  • Java多个线程顺序打印数字

    要求

    启动N个线程, 这N个线程要不间断按顺序打印数字1-N. 将问题简化为3个线程无限循环打印1到3

    方法一: 使用synchronized

    三个线程无序竞争同步锁, 如果遇上的是自己的数字, 就打印. 这种方式会浪费大量的循环

    public class TestSequential1 {
        private volatile int pos = 1;
        private volatile int count = 0;
    
        public void one(int i) {
            synchronized (this) {
                if (pos == i) {
                    System.out.println("T-" + i + " " + count);
                    pos = i % 3 + 1;
                    count = 0;
                } else {
                    count++;
                }
            }
        }
    
        public static void main(String[] args) {
            TestSequential1 demo = new TestSequential1();
            for (int i = 1; i <=3; i++) {
                int j = i;
                new Thread(()->{
                    while(true) {
                        demo.one(j);
                    }
                }).start();
            }
        }
    }
    

    输出

    T-1 0
    T-2 5793
    T-3 5285
    T-1 2616
    T-2 33
    T-3 28
    T-1 22
    T-2 44
    T-3 6
    T-1 881
    T-2 118358
    T-3 247380
    T-1 30803
    T-2 29627
    T-3 52044
    ...
    

    方法二: 使用synchronized配合wait()和notifyAll()

    竞争同步锁时使用wait()和notifyAll(), 可以避免浪费循环

    public class TestSequential4 {
        private volatile int pos = 1;
        private volatile int count = 0;
        private final Object obj = new Object();
    
        public void one(int i) {
            System.out.println(i + " try");
            synchronized (obj) {
                System.out.println(i + " in");
                try {
                    while (pos != i) {
                        count++;
                        System.out.println(i + " wait");
                        obj.wait();
                    }
                    System.out.println("T-" + i + " " + count);
                    pos = i % 3 + 1;
                    count = 0;
                    obj.notifyAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args) {
            TestSequential4 demo = new TestSequential4();
            for (int i = 3; i >=1; i--) {
                int j = i;
                new Thread(()->{
                    while(true) {
                        demo.one(j);
                    }
                }).start();
            }
        }
    }
    

    输出

    3 try
    3 in
    3 wait
    2 try
    2 in
    2 wait
    1 try
    1 in
    T-1 2
    1 try
    1 in
    1 wait
    T-2 1
    2 try
    2 in
    2 wait
    T-3 1
    3 try
    3 in
    3 wait
    2 wait
    T-1 2
    1 try
    1 in
    1 wait
    T-2 1
    2 try
    2 in
    2 wait
    T-3 1
    3 try
    3 in
    3 wait
    2 wait
    T-1 2
    1 try
    1 in
    1 wait
    T-2 1
    2 try
    2 in
    2 wait
    T-3 1
    3 try
    3 in
    3 wait
    2 wait
    T-1 2
    1 try
    1 in
    1 wait
    T-2 1
    2 try
    2 in
    2 wait
    T-3 1
    3 try
    3 in
    3 wait
    2 wait
    T-1 2
    1 try
    1 in
    1 wait
    T-2 1
    2 try
    2 in
    2 wait
    T-3 1
    3 try
    3 in
    3 wait
    2 wait
    T-1 2
    1 try
    1 in
    1 wait
    T-2 1
    2 try
    2 in
    2 wait
    T-3 1
    3 try
    3 in
    3 wait
    2 wait
    T-1 2
    1 try
    1 in
    1 wait
    T-2 1
    2 try
    2 in
    2 wait
    T-3 1
    3 try
    3 in
    3 wait
    2 wait
    T-1 2
    1 try
    1 in
    1 wait
    T-2 1
    2 try
    2 in
    2 wait
    T-3 1
    3 try
    3 in
    3 wait
    2 wait
    T-1 2
    1 try
    1 in
    1 wait
    T-2 1
    2 try
    2 in
    2 wait
    T-3 1
    3 try
    3 in
    3 wait
    2 wait
    T-1 2
    ...
    

    .

    方法三: 使用可重入锁

    用Lock做, 非公平锁, 三个线程竞争, 如果遇上的是自己的数字, 就打印. 这种方式也会浪费大量的循环

    public class TestSequential2 {
        private final Lock lock = new ReentrantLock();
        private volatile int pos = 1;
        private volatile int count = 0;
    
        public void one(int i) {
            lock.lock();
            if (pos == i) {
                System.out.println("T-" + i + " " + count);
                pos = i % 3 + 1;
                count = 0;
            } else {
                count++;
            }
            lock.unlock();
        }
    
        public static void main(String[] args) {
            TestSequential2 demo = new TestSequential2();
            for (int i = 1; i <=3; i++) {
                int j = i;
                new Thread(()->{
                    while(true) {
                        demo.one(j);
                    }
                }).start();
            }
        }
    }
    

    输出

    T-1 0
    T-2 0
    T-3 323
    T-1 54
    T-2 68964
    T-3 97642
    T-1 6504
    T-2 100603
    T-3 6989
    T-1 1313
    T-2 0
    T-3 183741
    T-1 233
    T-2 5081
    T-3 164367
    ..
    

    .

    方法四: 使用可重入锁, 启用公平锁

    和3一样, 但是使用公平锁, 这种情况下基本上可以做到顺序执行, 偶尔会产生多一次循环

    private final Lock lock = new ReentrantLock(true);
    

    输出

    T-1 0
    T-2 0
    T-3 0
    T-1 0
    T-2 0
    T-3 0
    T-1 0
    T-2 0
    T-3 0
    T-1 0
    T-2 0
    T-3 1
    T-1 1
    T-2 1
    T-3 1
    ...
    

    .

    方法五: 使用Condition

    每个线程如果看到不是自己的计数, 就await(), 如果是自己的计数, 就完成打印动作, 再signalAll()所有其他线程去继续运行, 自己在下一个循环后, 即使又继续执行, 也会因为计数已经变了而await.

    如果ReentrantLock构造参数使用true, 可以基本消除 ~await 这一步的输出.

    public class ReentrantLockCondition2 {
        private static Lock lock = new ReentrantLock();
        private static Condition condition = lock.newCondition();
        private volatile int state = 1;
    
        private void handle(int state) {
            lock.lock();
            try {
                while(true) {
                    while(this.state != state) {
                        System.out.println(state + " ~await");
                        condition.await();
                    }
                    System.out.println(state);
                    this.state = state % 3 + 1;
                    condition.signalAll();
                    System.out.println(state + " await");
                    condition.await();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    
        public static void main(String[] args) {
            ReentrantLockCondition2 rlc = new ReentrantLockCondition2();
            new Thread(()->rlc.handle(1)).start();
            new Thread(()->rlc.handle(2)).start();
            new Thread(()->rlc.handle(3)).start();
        }
    }
    

    .

    方法六: 使用多个Condition

    给每个线程不同的condition. 这个和4的区别是, 可以用condition.signal()精确地通知对应的线程继续执行(在对应的condition上await的线程, 可能是多个). 这种情况下是可以多个线程都不unlock锁的情况下进行协作的. 注意下面的while(true)循环是在lock.lock()方法内部的.

    public class ReentrantLockCondition {
        private static Lock lock = new ReentrantLock();
        private static Condition[] conditions = {lock.newCondition(), lock.newCondition(), lock.newCondition()};
        private volatile int state = 1;
    
        private void handle(int state) {
            lock.lock();
            try {
                while(true) {
                    while(this.state != state) {
                        conditions[state - 1].await();
                    }
                    System.out.println(state);
                    this.state = state % 3 + 1;
                    conditions[this.state - 1].signal();
                    conditions[state - 1].await();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    
        public static void main(String[] args) {
            ReentrantLockCondition rlc = new ReentrantLockCondition();
            new Thread(()->rlc.handle(1)).start();
            new Thread(()->rlc.handle(2)).start();
            new Thread(()->rlc.handle(3)).start();
        }
    }
    

    .

  • 相关阅读:
    安装paramiko
    pip安装
    json
    java的枚举2
    java学习笔记1
    Myeclipse配置tomcat,以及简单的Myeclipse的配置
    Net分布式系统之四:RabbitMQ消息队列应用
    Net分布式系统之三:Keepalived+LVS+Nginx负载均衡之高可用
    Net分布式系统之二:CentOS系统搭建Nginx负载均衡(下)
    Spring简介
  • 原文地址:https://www.cnblogs.com/milton/p/11311148.html
Copyright © 2011-2022 走看看