zoukankan      html  css  js  c++  java
  • Java多线程中run(), start(), join(), wait(), yield(), sleep()的使用

    Run

    每个Thread中需要实现的方法, 如果直接调用的话, 会是和单线程一样的效果, 要另起线程需要使用start(). 

    start

    新起线程调用run(). 主线程不等待直接往下执行

    Yield

    Yield会告诉jvm, 它愿意让出当前的处理器使用, 让其他线程被执行. 这意味着它并非在执行非常紧急的任务, 这只是一个hit, 可能会被忽略, 可能并不会发生任何作用. 需要有详细的profiling和benchmarking来保证这个调用达到预期的效果.

    • Yield是一个静态和原生的方法
    • Yield告诉当前线程, 给予线程池中同等优先级的其他线程被执行的机会.
    • Yield并不保证会立即将当前正在执行的线程状态转变为runnable.
    • Yield只会将一个线程的状态从Running变成Runnable, 而不是wait或blocked状态.

    Join

    • 线程实例的join调用, 可以让这个线程执行的开始被关联到另一个线程执行的结束上, 这样直到另一个线程结束后这个线程才会开始执行. 如果对一个线程调用了join, 那么当前running的线程会被block, 直到那个线程执行结束.
    • 如果在join中设置了timeout, 那么在timeout后会取消join, 当timeout时, 主线程会变成和任务线程一样的执行候选, 但是这个时间准确度取决于操作系统, 并不能保证是精确的.
    • join和sleep一样, 会相应interrupt并抛出一个InterruptedException

    如果有一个Thread a, 在a.start()后面(可以使用thread.isAlive()判断). 使用a.join() 可以使主线程等待a执行完. 如果同时有多个线程a, b, c, 而d需要等abc执行完后才能执行, 可以在d start之前使用a.join, b.join, c.join, 也可以把a, b, c的start放到d的run方法里面, 使用a.join, b.join, c.join, 可以用参数设置timeout时间.

    class JoiningThread extends Thread {
        // NOTE: UNTESTED!
        private String name;
        private Thread nextThread;
    
        public JoiningThread(String name) {
            this(name, null);
        }
    
        public JoiningThread(String name, Thread other) {
            this.name = name;
            this.nextThread = other;
        }
    
        public String getName() {
            return name;
        }
    
        @Override
        public void run() {
            System.out.println("Hello I'm thread ".concat(getName()));
            if (nextThread != null) {
                while(nextThread.isAlive()) {
                    try {
                        nextThread.join();
                    } catch (InterruptedException e) {
                        // ignore this
                    }
                }
            }
            System.out.println("I'm finished ".concat(getName()));
        }
    }
    

    使用的时候

    public static void main(String[] args) {
        Thread d = WaitingThread("d");
        Thread c = WaitingThread("c", d);
        Thread b = WaitingThread("b", c);
        Thread a = WaitingThread("a", b);
    
        a.start();
        b.start();
        c.start();
        d.start();
    
        try {
            a.join();
        } catch (InterruptedException e) {}
    }
    

    sleep(): 需要时间作为参数, 可以被interrupt.

    wait(): wait会释放当前持有的锁, 并进入sleep状态. 和join()的区别是, wait需要额外的notify来终止. 

    notify(): synchronized锁定的是什么资源, 就在什么资源上调用notify. notify会唤醒在当前锁定对象上使用了wait()的一个线程. 要注意的是, 调用notify时并未释放锁定的对象资源, 它只是告诉等待的线程, 你可以醒过来了. 而锁的释放要等到synchronized代码块执行的结束. 所以如果对一个资源调用了notify(), 而调用者本身还需要10秒中才能完成synchronized的代码块, 被唤醒的线程还需要再等10秒才能继续执行.

    notifyAll(): 会唤醒当前锁定对象上等待的所有线程, 最高优先级的线程会拿到对象锁并继续执行(这不是完全保证的). 其他和notify是一样的.

    上面的类可以改写为

    class WaitingThread extends Thread {
        // NOTE: UNTESTED!
    
        private Thread previousThread;
        private String name;
    
        public WaitingThread(String name) {
            this(name, null);
        }
    
        public WaitingThread(String name, Thread other) {
            this.name = name;
            this.previousThread = other;
        }
    
        public String getName() {
            return name;
        }
    
        @Override
        public void run() {
            System.out.println("Hello I'm thread ".concat(getName()));
            // Do other things if required
    
            // Wait to be woken up
            while(true) {
                synchronized(this) {
                    try {
                        wait();
                        break;
                    } catch (InterruptedException e) {
                        // ignore this
                    }
                }
            }
    
            System.out.println("I'm finished ".concat(getName()));
    
            // Wake up the previous thread
            if (previousThread != null) {
                synchronized(previousThread) {
                    previousThread.notify();
                }
            }
        }
    }
    

    对于 synchronized, wait 和 notifyAll 的测试. 其中Producer模拟一个队列生产者, Consumer1和Consumer2模拟队列消费者, 队列是同步对象, 得到锁的线程, 会通过wait()或notifyAll()通知其他线程继续尝试得到锁.

    Producer.java 

    class Producer implements Runnable {
        private final List<Integer> taskQueue;
        private final int MAX_CAPACITY;
    
        public Producer(List<Integer> sharedQueue, int size) {
            this.taskQueue = sharedQueue;
            this.MAX_CAPACITY = size;
        }
    
        @Override
        public void run() {
            int counter = 0;
            while (true) {
                try {
                    produce(counter++);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
        }
    
        private void produce(int i) throws InterruptedException {
            System.out.println(Thread.currentThread().getName() + ": produce()");
            synchronized (taskQueue) {
                System.out.println(Thread.currentThread().getName() + ": produce().synchronized >>");
                while (taskQueue.size() == MAX_CAPACITY) {
                    System.out.println(Thread.currentThread().getName() + ": produce().synchronized ||");
                    taskQueue.wait();
                }
    
                Thread.sleep(500 + (long)(Math.random() * 500));
                taskQueue.add(i);
                System.out.println(Thread.currentThread().getName() + ": Produced: " + i);
                taskQueue.notifyAll();
                System.out.println(Thread.currentThread().getName() + ": produce().synchronized <<");
            }
        }
    }
    

    Consumer.java

    class Consumer implements Runnable {
        private final List<Integer> taskQueue;
    
        public Consumer(List<Integer> sharedQueue) {
            this.taskQueue = sharedQueue;
        }
    
        @Override
        public void run() {
            while (true) {
                try {
                    consume();
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
        }
    
        private void consume() throws InterruptedException {
            System.out.println(Thread.currentThread().getName() + ": consume()");
            synchronized (taskQueue) {
                System.out.println(Thread.currentThread().getName() + ": consume().synchronized >>");
                while (taskQueue.isEmpty()) {
                    System.out.println(Thread.currentThread().getName() + ": consume().synchronized ||");
                    taskQueue.wait();
                }
                Thread.sleep(500 + (long)(Math.random() * 500));
                int i = (Integer) taskQueue.remove(0);
                System.out.println(Thread.currentThread().getName() + ": Consumed: " + i);
                taskQueue.notifyAll();
                System.out.println(Thread.currentThread().getName() + ": consume().synchronized <<");
            }
        }
    }

    ProducerConsumerExample.java

    public class ProducerConsumerExample {
        public static void main(String[] args) {
            List<Integer> taskQueue = new ArrayList<Integer>();
            int MAX_CAPACITY = 5;
            Thread tProducer = new Thread(new Producer(taskQueue, MAX_CAPACITY), "Producer");
            Thread tConsumer = new Thread(new Consumer(taskQueue), "Consumer1");
            Thread tConsumer2 = new Thread(new Consumer(taskQueue), "Consumer2");
            tProducer.start();
            tConsumer.start();
            tConsumer2.start();
        }
    }
    
  • 相关阅读:
    Windows Server 2012上PHP运行环境搭建的简易教程(Win08适用)
    Windows 8.1 系统ISO镜像下载或自Win8应用商店升级方法
    dojo布局(layout)
    dojo创建tree
    Postgres SQL学习笔记
    PostGIS ShapeFile 导入数据
    利用 PortableBasemapServer 发布地图服务
    Fortran 笔记
    ArcMap 操作笔记
    gdal编译C#开发版本
  • 原文地址:https://www.cnblogs.com/milton/p/4215111.html
Copyright © 2011-2022 走看看