zoukankan      html  css  js  c++  java
  • 多线程---线程间的通信

    1 . wait() 方法使当前执行代码的线程进行等待,将当前线程置入"预执行队列",并且在wait()方法所在处停止执行,直到接到通知或者中断。 在调用wait之前,线程必须获得该对象的对象级别锁,即只能在同步方法或者同步代码块中才能调用wait方法调用wait()方法后当前线程自动释放锁。在从wait()返回之前,线程与其他线程竞争重新获得锁。

    2 . notify() 用来通知那些可能等待该对象的对象锁的其他线程,如果有多个线程等待,则由线程规划器随机选出其中一个呈wait状态的线程对其发出notify, 并使它获取该对象的对象锁,值得注意的是在执行notify方法后当前线程不会马上释放该对象锁,呈wait状态的线程也不能马上获得该对象锁,要等到执行notify方法的线程将线程执行完,也就是退出synchronized代码块后,当前线程才会释放锁,而呈wait状态的线程才可以获取该对象锁。当第一个获得了该对象锁的线程运行完毕之后它会释放掉该对象锁,此时如果对象没有再次使用notify方法,即便该对象已经空闲,其他wait状态等待的线程由于没有得到该对象的通知,还会阻塞在wait状态,直到这个对象发出一个notify或者notifyAll. notify方法也要在同步方法或者同步代码块中才能调用,线程也必须获得该对象的对象级别锁

    3 . 执行完同步代码块就会释放对象的锁;在执行同步代码块的过程中,遇到异常而导致线程终止锁也会被释放;在执行同步代码块的过程中,执行了锁所属对象的wait()方法,这个线程将会释放对象锁,而此线程对象将会进入线程等待池中等待被唤醒。

    4.方法join()的作用是等待线程对象被销毁。也就是使所属线程对象x正常执行run()方法中的任务而使当前线程z无限期的阻塞,等待x销毁后再继续执行z后面的代码。

    public class Test extends Thread{
    
        @Override
        public void run() {
            int number = (int)(Math.random()*1000);
            System.out.println(Thread.currentThread().getName()+" thread will sleep " + number + "ms");
            try {
                Thread.sleep(number);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
    
        public static void main(String[] args) throws InterruptedException {
            Test test = new Test();
            test.setName("test");
            test.start();
            test.join();
            System.out.println("main thread execute after test thread end");
        }
    }
    
    运行结果为:
    test    thread will sleep 595ms
    main thread execute after test thread end
    
    如果不调用join方法输出结果为:
    main thread execute after test thread end
    test thread will sleep 94ms

    5 .方法join(long millis)和方法sleep(long millis)都有使线程等待一段时间的作用,但是join方法内部是使用wait方法实现的,所以join方法具有释放锁的特点,而sleep方法不会释放锁

    6 . 关键字synchronized和wait(),notify()/notifyAll()方法一起使用可以实现等待/通知机制,类ReentrantLock也可以实现同样的功能,但需要借助Condition对象来完成,Condition对象具有更好的灵活性,使用它可以实现多路通知功能,也就是一个Lock对象里面可以创建多个Condition(即对象监视器)对象实例,线程对象可以注册在指定的Condition中,从而有选择的进行通知,在线程调度上更灵活。而在使用notify()/notifyAll()方法进行通知的时候,被通知的线程却是由JVM随机选择的。

    • 使用synchronized和wait,notify实现等待通知机制
    public class WaitNotify1 {
    
        public void waitMethod() {
            System.out.println("  wait time begin at " + System.currentTimeMillis() / 1000);
            synchronized (this) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("  wait time   end at " + System.currentTimeMillis() / 1000);
        }
    
        public void notifyMethod() {
            System.out.println("notify time begin at " + System.currentTimeMillis() / 1000);
            synchronized (this) {
                this.notify();
            }
    
            System.out.println("notify time   end at " + System.currentTimeMillis() / 1000);
        }
    
        public static void main(String[] args) throws InterruptedException {
            WaitNotify1 wn1 = new WaitNotify1();
            // 使用匿名内部类的方式启动两个线程分别调用wn1对象的waitMethod和notifyMethod
            new Thread(new Runnable() {
                @Override
                public void run() {
                    wn1.waitMethod();
    
                }
            }).start();
    
            Thread.sleep(1000);
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    wn1.notifyMethod();
    
                }
            }).start();
    
            /**
             * 打印结果为: 
             *   wait time begin at 1493194588 
             * notify time begin at 1493194589
             * notify time   end at 1493194589 
             *   wait time   end at 1493194589
             * 
             */
    
        }
    
    }
    • 使用ReentrantLock和Condition对象实现等待-通知机制
    public class WaitNotify2 {
    
        private Lock lock = new ReentrantLock();
        private Condition con = lock.newCondition();
    
        public void waitMethod() {
    
            try {
                lock.lock();// 获得对象锁
                System.out.println("  wait time begin at " + System.currentTimeMillis() / 1000);
                con.await();// 线程进入等待
                System.out.println("  wait time   end at " + System.currentTimeMillis() / 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    
    
        public void notityMethod(){
            try {
                lock.lock();
                System.out.println("notify time begin at " + System.currentTimeMillis() / 1000);
                con.signal();// 唤醒线程
                System.out.println("notify time   end at " + System.currentTimeMillis() / 1000);
            } finally{
                lock.unlock();
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            WaitNotify2 wn2 = new WaitNotify2();
            Thread4 thread = new Thread4(wn2);
            thread.start();
            Thread.sleep(1000);
            wn2.notityMethod();
        }
    
    
        /**
         * 打印结果为: 
         *   wait time begin at 1493194430 
         * notify time begin at 1493194431
         * notify time   end at 1493194431 
         *   wait time   end at 1493194431
         * 
         */
    
    }
    
    class Thread4 extends Thread {
        private WaitNotify2 wn2;
    
        public Thread4(WaitNotify2 wn2) {
            this.wn2 = wn2;
        }
    
        @Override
        public void run() {
            wn2.waitMethod();
        }
    
    }

    7 . 生产者-消费者模式:
    (1) 使用synchronized与wait,notify实现生产者-消费者模式

    public class ProducersAndConsumers1 {
    
        private List<String> list = new ArrayList<>();
    
        public synchronized void produce() {
            try {
                while (list.size() == 1) {
                    System.out.println(Thread.currentThread().getName() + " begin waiting ");
                    this.wait();
                    System.out.println(Thread.currentThread().getName() + " end   waiting ");
                }
                list.add("nulo");
                this.notifyAll();
                System.out.println("produced by " + Thread.currentThread().getName() + ",now size = " + list.size());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public synchronized String consume() {
            String value = "";
            try {
                while (list.size() == 0) {
                    System.out.println(Thread.currentThread().getName() + " begin waiting ");
                    this.wait();
                    System.out.println(Thread.currentThread().getName() + " end   waiting ");
                }
                value = list.get(0);
                list.remove(0);
                this.notifyAll();
                System.out.println(
                        "consumed by " + Thread.currentThread().getName() + ",now size = " + list.size());
            } catch (Exception e) {
                e.printStackTrace();
            }
            return value;
        }
    
        public static void main(String[] args) throws InterruptedException {
            ProducersAndConsumers1 pool = new ProducersAndConsumers1();
    
            // 一生产一消费
            new ProducerThread("producer",pool).start();
            new ConsumerThread("consumer",pool).start();
    
            /**
             * 打印结果如下: 
             * consumer begin waiting 
             * producer end waiting 
             * produced by producer,now size = 1 
             * producer begin waiting 
             * consumer end waiting
             * consumed by consumer,now size = 0 
             * consumer begin waiting 
             * producer end waiting
             * produced by producer,now size = 1
             * producer begin waiting
             * consumer end   waiting 
             * consumed by consumer,now size = 0 
             * consumer begin waiting 
             * 
             */
    
    
    
    
    
            // 一生产多消费
            /*new ProducerThread("producer",pool).start();
            new ConsumerThread("consumer1",pool).start();
            new ConsumerThread("consumer2",pool).start();*/
    
            // 多生产一消费
            /*new ProducerThread("producer1",pool).start();
            new ProducerThread("producer2",pool).start();
            new ConsumerThread("consumer",pool).start();*/
    
            // 多生产多消费
            /*new ProducerThread("producer1",pool).start();
            new ProducerThread("producer2",pool).start();
            new ConsumerThread("consumer1",pool).start();
            new ConsumerThread("consumer2",pool).start();*/
    
    
        }
    }
    
    /**
     * 
     * 生产者线程
     * 
     * @Description
     * @author niepei
     * @date 2017年4月26日 下午4:44:17
     * @version V1.3.1
     */
    class ProducerThread extends Thread {
        private ProducersAndConsumers1 pool;
    
        public ProducerThread(String name,ProducersAndConsumers1 pool) {
            super(name);
            this.pool = pool;
        }
    
        @Override
        public void run() {
            while (true) {
                pool.produce();
            }
    
        }
    }
    
    /**
     * 
     * 消费者线程
     * 
     * @Description
     * @author niepei
     * @date 2017年4月26日 下午4:44:29
     * @version V1.3.1
     */
    class ConsumerThread extends Thread {
        private ProducersAndConsumers1 pool;
    
        public ConsumerThread(String name,ProducersAndConsumers1 pool) {
            super(name);
            this.pool = pool;
        }
    
        @Override
        public void run() {
            while (true) {
                pool.consume();
            }
    
        }
    }

    (2) 使用ReentrantLock和Condition对象实现生产者-消费者模式

    public class ProducersAndConsumers2 {
    
        private List<String> list = new ArrayList<>();
    
        private Lock lock = new ReentrantLock();
    
        private Condition con = lock.newCondition();
    
        public void produce(){
            try {
                lock.lock();
                while(list.size()==1){
                    System.out.println(Thread.currentThread().getName() + " begin waiting ");
                    con.await();
                    System.out.println(Thread.currentThread().getName() + "   end waiting ");
                }
                list.add("nulo");
                con.signalAll();
                System.out.println("produced by " + Thread.currentThread().getName() + ",now size = " + list.size());
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    
        public String consume(){
            String value = "";
            try {
                lock.lock();
                while(list.size()==0){
                    System.out.println(Thread.currentThread().getName() + " begin waiting ");
                    con.await();
                    System.out.println(Thread.currentThread().getName() + "   end waiting ");
                }
                list.remove(0);
                con.signalAll();
                System.out.println("consumed by " + Thread.currentThread().getName() + ",now size = " + list.size());
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
            return value;
        }
    
        public static void main(String[] args) throws InterruptedException {
            ProducersAndConsumers1 pool = new ProducersAndConsumers1();
    
            // 一生产一消费
            new ProducerThread("producer",pool).start();
            new ConsumerThread("consumer",pool).start();
    
            /**
             * 打印结果如下: 
             * consumer begin waiting 
             * producer end waiting 
             * produced by producer,now size = 1 
             * producer begin waiting 
             * consumer end waiting
             * consumed by consumer,now size = 0 
             * consumer begin waiting 
             * producer end waiting
             * produced by producer,now size = 1
             * producer begin waiting
             * consumer end   waiting 
             * consumed by consumer,now size = 0 
             * consumer begin waiting 
             */
    
    
        }
    
    }
    
    
    /**
     * 
     * 生产者线程
     * 
     * @Description
     * @author niepei
     * @date 2017年4月26日 下午4:44:17
     * @version V1.3.1
     */
    class ProducerThread extends Thread {
        private ProducersAndConsumers1 pool;
    
        public ProducerThread(String name,ProducersAndConsumers1 pool) {
            super(name);
            this.pool = pool;
        }
    
        @Override
        public void run() {
            while (true) {
                pool.produce();
            }
    
        }
    }
    
    /**
     * 
     * 消费者线程
     * 
     * @Description
     * @author niepei
     * @date 2017年4月26日 下午4:44:29
     * @version V1.3.1
     */
    class ConsumerThread extends Thread {
        private ProducersAndConsumers1 pool;
    
        public ConsumerThread(String name,ProducersAndConsumers1 pool) {
            super(name);
            this.pool = pool;
        }
    
        @Override
        public void run() {
            while (true) {
                pool.consume();
            }
    
        }
    }

    8 . 类ThreadLocal可以使每个线程绑定自己的值,它解决的是变量在各个线程之间的隔离问题,也就是不同线程拥有自己的值,不同线程中的值是可以放入ThreadLocal中保存的

    public class UseThreadLocal {
    
        public static ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<>();
    
        private ThreadLocal<String> threadLocal = new ThreadLocal<>();
    
        public static void main(String[] args) throws InterruptedException {
            function1();
            /**
             * 打印结果如下: 
             * THREAD_LOCAL in <main> is null 
             * THREAD_LOCAL in <test> is null 
             * THREAD_LOCAL in <test> is test 
             * THREAD_LOCAL in <main> is main          
             */
    
    
            new UseThreadLocal().function2();
            /**
             * 打印结果如下: 
             * threadLocal in <main> is null
             * threadLocal in <test> is null
             * threadLocal in <test> is test
             * threadLocal in <main> is main
             */
    
        }
    
        public static void function1() throws InterruptedException {
            System.out.println("THREAD_LOCAL in <" + Thread.currentThread().getName() + "> is " + THREAD_LOCAL.get());
            THREAD_LOCAL.set("main");
            Thread a = new Thread("test") {
                @Override
                public void run() {
                    System.out.println(
                            "THREAD_LOCAL in <" + Thread.currentThread().getName() + "> is " + THREAD_LOCAL.get());
                    THREAD_LOCAL.set("test");
                    System.out.println(
                            "THREAD_LOCAL in <" + Thread.currentThread().getName() + "> is " + THREAD_LOCAL.get());
                }
            };
            a.start();
            a.join();
            System.out.println("THREAD_LOCAL in <" + Thread.currentThread().getName() + "> is " + THREAD_LOCAL.get());
        }
    
        public void function2() throws InterruptedException {
    
            System.out.println("threadLocal in <" + Thread.currentThread().getName() + "> is " + threadLocal.get());
            threadLocal.set("main");
            Thread a = new Thread("test") {
                @Override
                public void run() {
                    System.out.println("threadLocal in <" + Thread.currentThread().getName() + "> is " + threadLocal.get());
                    threadLocal.set("test");
                    System.out.println("threadLocal in <" + Thread.currentThread().getName() + "> is " + threadLocal.get());
                }
            };
            a.start();
            a.join();
            System.out.println("threadLocal in <" + Thread.currentThread().getName() + "> is " + threadLocal.get());
        }
    
    }
  • 相关阅读:
    NHibernate中的Clear和Flush方法
    什么是POCO类
    node-vuecli 脚手架安装
    layui表单引入ueditor遇坑记
    PHP的九个超全局变量
    PHP的八个魔术常量
    PHP的七个数组指针函数
    TP6.0多应用模式隐藏路由中的应用名
    TP6.0中的密码验证逻辑、验证器的使用
    Vue 侦听器 watch
  • 原文地址:https://www.cnblogs.com/pepper7/p/7196910.html
Copyright © 2011-2022 走看看