当前位置:首页 > Java技术 > Java多线程中run(), start(), join(), wait(), yield(), sleep()的使用

Java多线程中run(), start(), join(), wait(), yield(), sleep()的使用

2022年11月08日 09:20:38Java技术8

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();
    }
}

 

 

 

 

来源链接:https://www.cnblogs.com/milton/p/4215111.html

版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。

2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。


本文链接:https://www.javaclub.cn/java/68466.html

分享给朋友:

“Java多线程中run(), start(), join(), wait(), yield(), sleep()的使用” 的相关文章

图解 Java IO : 二、FilenameFilter源码

图解 Java IO : 二、FilenameFilter源码

Writer      :BYSocket(泥沙砖瓦浆木匠) 微         博:BYSocket 豆  &...

java泛型通配符详解

java泛型通配符详解

前言 泛型带来的好处 泛型中通配符 常用的 T,E,K,V,? ?无界通配符 上界通配符 < ? extends E> 下界通配符 < ? super E>...

java中的内部类总结

java中的内部类总结,包括静态内部类、私有内部类、方法内部类等 内部类不是很好理解,但说白了其实也就是一个类中还包含着另外一个类 如同一个人是由大脑、肢体、器官等身体结果组成,而内部类相当于其中的某个器官之一,例如心脏:它也有自己的属性和行为(血液、跳动)...

Java并发包基石

Java并发包基石

目录     1 基本实现原理       1.1 如何使用        1.2 设计思想     2 自定义同步器       2.1 同步器代码实现        2.2 同步器代码测试     3 源码分析       ...

java synchronized详解

记下来,很重要。 Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。      一、当两个并发线程访问同一个对象object中的这个synchronized(this)同...

Java 基础【06】 Super 用法

     路漫漫其修远兮,吾将上下而求索。——屈原《离骚》      昨天写this用法总结的时候,突然产生了一个问题,请教别人之后,有了自己的一点认识。还是把它写下来,为大家更好的认识提供一点思路。 1)有人写了...

Java 干货之深入理解Java泛型

Java 干货之深入理解Java泛型

一般的类和方法,只能使用具体的类型,要么是基本类型,要么是自定义的类。如果要编写可以应用多中类型的代码,这种刻板的限制对代码得束缚会就会很大。 ---《Thinking in Java》 泛型大家都接触的不少,但是由于Java 历史的原因,Java 中的泛型一直...

JAVA | Java 解决跨域问题

JAVA | Java 解决跨域问题

JAVA | Java 解决跨域问题 Table of Contents 引言 什么是跨域(CORS) 什么情况会跨域 解决方案 前端解决方案 后端解决方案...

Java Calendar类的使用总结

  在实际项目当中,我们经常会涉及到对时间的处理,例如登陆网站,我们会看到网站首页显示XXX,欢迎您!今天是XXXX年。。。。某些网站会记录下用户登陆的时间,比如银行的一些网站,对于这些经常需要处理的问题,Java中提供了Calendar这个专门用于对日期进行操作的类,那么这个类有什么...

Java文件操作大全

  //1.创建文件夹 //import java.io.*; File myFolderPath = new File(str1); try { if (!myFolderPath.exists()) {...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。