zoukankan      html  css  js  c++  java
  • java多线程-Thread

    大纲

    1. sleep
    2. yield
    3. join
    4. setDaemon
    • sleep:
    public static native void sleep(long millis) throws InterruptedException;
    sleep是本地静态方法。
    sleep的作用是让线程进入TIME_WAITING状态,参数是多少毫秒。
    class Test {
        public static void main(String[] args){
            Thread thread = new Thread(()->{
                try {
                    Thread.sleep(2000);
                    System.out.println("over");
                } catch (InterruptedException e) {
                    System.out.println("interrupt");
                }
            });
            thread.start();
        }
    }
    
    /**
     结果:2秒后看到over
     */
    sleep可被interrupt打断,抛出InterruptedException。
    class Test {
        public static void main(String[] args){
            Thread thread = new Thread(()->{
                try {
                    Thread.sleep(2000);
                    System.out.println("over");
                } catch (InterruptedException e) {
                    System.out.println("interrupt");
                }
            });
            thread.start();
            thread.interrupt();
        }
    }
    
    /**
     结果:立刻看到interrupt
     */

    注意:sleep方法并不释放锁。

    • yield:
    public static native void yield();

    yield是一个本地静态方法。

    yield表示当前线程申请交出执行权,但并不是一定会交出,依赖于系统的线程调度。

    因此该方法并不稳定

    class Test {
        public static void main(String[] args) throws InterruptedException {
            TestYield t0 = new TestYield("thread0");
            TestYield t1 = new TestYield("thread1");
            t0.start();
            t1.start();
        }
    }
    
    class TestYield extends Thread {
        public TestYield(String name) {
            super(name);
        }
    
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                if (Thread.currentThread().getName().equals("thread0")&&i==5) {
                    yield();
                }
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
    /**
     结果:t0打印4后会交出执行权,一般不会连续打印thread0:4 thread0:5
     */

    注意:yield 方法放弃执行权但并不释放锁

    • join:

    之前看了一些博客说join就是把多线程变成单线程,其实并不是,执行join还是多线程。

    class Test {
        public static void main(String[] args) throws InterruptedException {
            TestJoin t0 = new TestJoin();
            TestJoin t1 = new TestJoin();
            t0.start();
            t1.start();
            t0.join();
            for(int i=0;i<100;i++){
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
    
    class TestJoin extends Thread{
        @Override
        public void run(){
            for(int i=0;i<100;i++){
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
    /**
     结果:t0.t1线程交替打印至t0执行结束,然后开始t1,main线程交替打印。
     */

    结合源码看看join做了什么。

    public final void join() throws InterruptedException {
            join(0);
    }
    public final synchronized void join(long millis)
        throws InterruptedException {
            long base = System.currentTimeMillis();
            long now = 0;
    
            if (millis < 0) {
                throw new IllegalArgumentException("timeout value is negative");
            }
    
            if (millis == 0) {
                while (isAlive()) {
                    wait(0);
                }
            } else {
                while (isAlive()) {
                    long delay = millis - now;
                    if (delay <= 0) {
                        break;
                    }
                    wait(delay);
                    now = System.currentTimeMillis() - base;
                }
            }
        }

    执行过程(这里讨论执行无参join方法,如果执行有参数join(xx),其实就是让main线程wait(xx)):

    1. main线程执行t0.join()。
    2. main线程执行join(),join()执行join(0),join(long millis)是一个同步方法。
    3. while(isAlive)这里的isAlive是t0的isAlive,如果t0存活,此时main线程持有t0的对象锁,执行wait。 (while确保了其他线程持有t0锁执行notifyAll后也无法唤醒main线程)
    4. main线程进入WAITING状态。
    5. t0,t1状态正常,交替执行至t0结束。
    6. t0结束后,由本地方法执行t0.notifyAll,main线程被唤醒。(源码中并看不到如何notifyAll的,线程结束后会执行一个本地方法notifyAll)
    7. 这时如果t1还没执行完成,main和t1交替执行。

    https://blog.csdn.net/erica_1230/article/details/69388742 中介绍了:线程结束时调用的本地方法notifyAll

    static void ensure_join(JavaThread* thread) {
      Handle threadObj(thread, thread->threadObj());
      assert(threadObj.not_null(), "Java thread object must exist");
      ObjectLocker lock(threadObj, thread);
      thread->clear_pending_exception();
      java_lang_Thread::set_stillborn(threadObj());
      java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);
      java_lang_Thread::set_thread(threadObj(), NULL);
      lock.notify_all(thread);
      thread->clear_pending_exception();
    }

    结论:当一个线程a执行线程b.join()则,线程a等待至线程b执行完毕后继续执行,这个过程并不影响其线程的执行。

    • setDaemon
    
    
    private boolean daemon = false;
    public final void setDaemon(boolean on) {
            checkAccess();
            if (isAlive()) {
                throw new IllegalThreadStateException();
            }
            daemon = on;
    }
    1. 线程的类型分为用户线程与守护线程,我们平时使用的一般是用户线程。
    2. 调用setDaemon(true)方法即可将线程设置问守护线程。注意isAlive方法判断该线程状态,因此setDaemon必须在线程start之前。
    3. 两者区别:用户线程运行结束,只剩下守护线程工作时虚拟机就会退出。所以说守护线程随时可能中断,而且随着用户线程消失而消失。
    4. 守护线程中创建的线程依然是守护线程。(源码中判断parent.isDaemon并把结果赋值给子线程)
  • 相关阅读:
    Java AbstractQueuedSynchronizer(AQS)
    CentOS Install Rancher & K3s
    CentOS Install Rancher & Kubernetes
    CentOS Install Kubernetes & Kubesphere
    支付宝小程序入门
    uni-app 抽奖
    APP上架
    uniapp微信小程序语音识别实现
    uniapp 安卓打包之导入的项目打包指导
    uniapp 支付宝 支付后不成功回调
  • 原文地址:https://www.cnblogs.com/liuboyuan/p/10120789.html
Copyright © 2011-2022 走看看