Java多线程 线程状态及转换 wait sleep yield join

时间:2022-09-24 01:22:21

Java多线程 线程状态及转换 wait sleep  yield  join

线程的状态转化关系
(1). 新建状态(New):新创建了一个线程对象。
(2). 就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
(3). 运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
(4). 阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
- 等待阻塞(WAITING):运行的线程执行wait()方法,JVM会把该线程放入等待池中。
- 同步阻塞(Blocked):运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
- 超时阻塞(TIME_WAITING):运行的线程执行sleep(long)或join(long)方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。
(5). 死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

下面的流程感觉有点问题,可以参考:

      、线程的实现有两种方式,一是继承Thread类,二是实现Runnable接口,但不管怎样,当我们new了这个对象后,线程就进入了初始状态;

  、当该对象调用了start()方法,就进入可运行状态;

  、进入可运行状态后,当该对象被操作系统选中,获得CPU时间片就会进入运行状态;

  、进入运行状态后情况就比较复杂了

  4.1、run()方法或main()方法结束后,线程就进入终止状态;

  4.2、当线程调用了自身的sleep()方法或其他线程的join()方法,就会进入阻塞状态(该状态既停止当前线程,但并不释放所占有的资源)。当sleep()结束或join()结束后,该线程进入可运行状态,继续等待OS分配时间片;

  4.3、线程调用了yield()方法,意思是放弃当前获得的CPU时间片,回到可运行状态,这时与其他进程处于同等竞争状态,OS有可能会接着又让这个进程进入运行状态;

  4.4、当线程刚进入可运行状态(注意,还没运行),发现将要调用的资源被synchroniza(同步),获取不到锁标记,将会立即进入锁池 状态,等待获取锁标记(这时的锁池里也许已经有了其他线程在等待获取锁标记,这时它们处于队列状态,既先到先得),一旦线程获得锁标记后,就转入可运行状态,等待OS分配CPU时间片;

  4.5、当线程调用wait()方法后会进入等待队列(进入这个状态会释放所占有的所有资源,与阻塞状态不同),进入这个状态后,是不能自动唤 醒的,必须依靠其他线程调用notify()或notifyAll()方法才能被唤醒(由于notify()只是唤醒一个线程,但我们由不能确定具体唤醒的是哪一个线程,也许我们需要唤醒的线程不能够被唤醒,因此在实际使用时,一般都用notifyAll()方法,唤醒有所线程),线程被唤醒后会进入锁 池,等待获取锁标记。

  总算全部回忆了一遍JDK1.5在API的使用上有了较好的改进,效率得到很大的提高,不过几个状态转换的原理还是一样。

==========================================================================

Java中关于线程的几个方法:

1.sleep()
使当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁。也就是如果有Synchronized同步块,其他线程仍然不同访问共享数据。注意该方法要捕获异常

比如有两个线程同时执行(没有Synchronized),一个线程优先级为MAX_PRIORITY,另一个为MIN_PRIORITY,如果没有Sleep()方法,只有高优先级的线程执行完成后,低优先级的线程才能执行;但当高优先级的线程sleep(5000)后,低优先级就有机会执行了。

总之,sleep()可以使低优先级的线程得到执行的机会,当然也可以让同优先级、高优先级的线程有执行的机会。

2.join()

join()方法使调用该方法的线程在此之前执行完毕,也就是等待调用该方法的线程执行完毕后再往下继续执行。注意该方法也要捕获异常。

等待调用join方法的线程结束,再继续执行。如:在线程a中,用b线程对象调用join()函数b.join();则a线程会在此处等待b线程执行结束后在接着执行。//主要用于等待b线程运行结束,若无此句,a则会执行完毕,导致结果不可预测。

3.yield()

它与sleep()类似,只是不能由用户指定暂停多长时间,并且yield()方法只能让同优先级的线程有执行的机会。

4.wait()和notify()、notifyAll()

这三个方法用于协调多个线程对共享数据的存取,所以必须在Synchronized语句块内使用这三个方法。前面说过Synchronized这个关键字用于保护共享数据,阻止其他线程对共享数据的存取。但是这样程序的流程就很不灵活了,如何才能在当前线程还没退出Synchronized数据块时让其他线程也有机会访问共享数据呢?此时就用这三个方法来灵活控制。

wait()方法使当前线程暂停执行并释放对象锁标志,让其他线程可以进入Synchronized数据块,当前线程被放入对象等待池中。当调用 notify()方法后,将从对象的等待池中移走一个任意的线程并放到锁标志等待池中,只有

锁标志等待池中的线程能够获取锁标志;如果锁标志等待池中没有线程,则notify()不起作用。

notifyAll()则从对象等待池中移走所有等待那个对象的线程并放到锁标志等待池中。

==============================================================

yield的例子:

public class Main{
    public static void main(String[] args) {
        Thread producer = new Producer();
        Thread consumer = new Consumer();

        producer.setPriority(Thread.MIN_PRIORITY); //Min Priority
        consumer.setPriority(Thread.MAX_PRIORITY); //Max Priority

        producer.start();
        consumer.start();
    }
}

class Producer extends Thread
{
    public void run()
    {
        for (int i = 0; i < 5; i++)
        {
            System.out.println("I am Producer : Produced Item " + i);
            Thread.yield();
        }
    }
}

class Consumer extends Thread
{
    public void run()
    {
        for (int i = 0; i < 5; i++)
        {
            System.out.println("I am Consumer : Consumed Item " + i);
            Thread.yield();
        }
    }
}

如果没有yield

 I am Consumer : Consumed Item 0
 I am Consumer : Consumed Item 1
 I am Consumer : Consumed Item 2
 I am Consumer : Consumed Item 3
 I am Consumer : Consumed Item 4
 I am Producer : Produced Item 0
 I am Producer : Produced Item 1
 I am Producer : Produced Item 2
 I am Producer : Produced Item 3
 I am Producer : Produced Item 4

有yield,是:

I am Consumer : Consumed Item 0
I am Producer : Produced Item 0
I am Producer : Produced Item 1
I am Consumer : Consumed Item 1
I am Consumer : Consumed Item 2
I am Consumer : Consumed Item 3
I am Producer : Produced Item 2
I am Producer : Produced Item 3
I am Producer : Produced Item 4
I am Consumer : Consumed Item 4

join的例子:

public class Main{
    public static void main(String[] args) throws InterruptedException {
            Thread t = new Thread(new Test());
            long start = System.currentTimeMillis();
            System.out.println(System.currentTimeMillis());
            t.start();
            t.join(1000);//等待线程t 1000毫秒
            System.out.println(System.currentTimeMillis()-start);//打印出时间间隔
            System.out.println("Main finished");//打印主线程结束
        }
}

class Test implements  Runnable{
    @Override
    public void run() {
        for (int i = 1; i <= 5; i++) {
            try {
                Thread.sleep(1000);//睡眠5秒,循环是为了方便输出信息
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("睡眠" + i);
            System.out.println(System.currentTimeMillis());
        }
        System.out.println("TestJoin finished");//t线程结束
    }
}
1488349325998
1001
Main finished
睡眠1
1488349327000
睡眠2
1488349328000
睡眠3
1488349329000
睡眠4
1488349330000
睡眠5
1488349331000
TestJoin finished

Test类进行修改:

class Test implements  Runnable{
    @Override
    public void run() {
        synchronized (Thread.currentThread()) {
            for (int i = 1; i <= 5; i++) {
                try {
                    Thread.sleep(1000);//睡眠5秒,循环是为了方便输出信息
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("睡眠" + i);
                System.out.println(System.currentTimeMillis());
            }
        }
        System.out.println("TestJoin finished");//t线程结束
    }
}
1488349545595
睡眠1
1488349546597
睡眠2
1488349547597
睡眠3
1488349548597
睡眠4
1488349549597
睡眠5
1488349550597
5002
Main finished
TestJoin finished

wait,sleep的区别

1)sleep 是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep 不会释放对象锁。
wait 是Object 类的方法,对此对象调用wait 方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify 方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。
1、这两个方法来自不同的类分别是Thread和Object
2、最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
3、wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用(使用范围)

synchronized(x){
  x.notify()
  //或者wait()
  }

4、sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常

package com.qhong;

import java.util.Date;

public class Main {
    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            synchronized (Wait.class) {
                try {
                    System.out.println(new Date() + " Thread1 is running");
                    Wait.class.wait();
                    System.out.println(new Date() + " Thread1 ended");
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        });
        thread1.start();

        Thread thread2 = new Thread(() -> {
            synchronized (Wait.class) {
                try {
                    System.out.println(new Date() + " Thread2 is running");
                    Wait.class.notify();
                    // Don't use sleep method to avoid confusing
                    for(long i = 0; i < 200000; i++) {
                        for(long j = 0; j < 100000; j++) {}
                    }
                    System.out.println(new Date() + " Thread2 release lock");
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }

            for(long i = 0; i < 200000; i++) {
                for(long j = 0; j < 100000; j++) {}
            }
            System.out.println(new Date() + " Thread2 ended");
        });

        // Don't use sleep method to avoid confusing
        for(long i = 0; i < 200000; i++) {
            for(long j = 0; j < 100000; j++) {}
        }
        thread2.start();
    }
}

class Wait {

}

Output:

Fri Mar 17 10:32:23 CST 2017 Thread1 is running
Fri Mar 17 10:32:30 CST 2017 Thread2 is running
Fri Mar 17 10:32:37 CST 2017 Thread2 release lock
Fri Mar 17 10:32:37 CST 2017 Thread1 ended
Fri Mar 17 10:32:43 CST 2017 Thread2 ended

hread1执行wait后,暂停执行
thread2执行notify后,thread1并没有继续执行,因为此时thread2尚未释放锁,thread1因为得不到锁而不能继续执行
thread2执行完synchronized语句块后释放锁,thread1得到通知并获得锁,进而继续执行

Sleep:

sleep方法告诉操作系统至少指定时间内不需为线程调度器为该线程分配执行时间片,并不释放锁(如果当前已经持有锁)。实际上,调用sleep方法时并不要求持有任何锁。

package com.qhong;

import java.util.Date;

public class Main {
    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            synchronized (Sleep.class) {
                try {
                    System.out.println(new Date() + " Thread1 is running");
                    Thread.sleep(2000);
                    System.out.println(new Date() + " Thread1 ended");
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        });
        thread1.start();

        Thread thread2 = new Thread(() -> {
            synchronized (Sleep.class) {
                try {
                    System.out.println(new Date() + " Thread2 is running");
                    Thread.sleep(2000);
                    System.out.println(new Date() + " Thread2 ended");
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }

            for(long i = 0; i < 200000; i++) {
                for(long j = 0; j < 100000; j++) {}
            }
        });

        // Don't use sleep method to avoid confusing
        for(long i = 0; i < 200000; i++) {
            for(long j = 0; j < 100000; j++) {}
        }
        thread2.start();
    }
}

class Sleep {

}

Output:

Fri Mar 17 10:38:44 CST 2017 Thread1 is running
Fri Mar 17 10:38:46 CST 2017 Thread1 ended
Fri Mar 17 10:38:51 CST 2017 Thread2 is running
Fri Mar 17 10:38:53 CST 2017 Thread2 ended

http://blog.csdn.net/jiafu1115/article/details/6804386

http://blog.csdn.net/huang_xw/article/details/7316354

http://gityuan.com/2016/01/03/java-thread-wait-sleep/

http://www.cnblogs.com/DreamSea/archive/2012/01/16/2263844.html

http://lavasoft.blog.51cto.com/62575/99153/

http://dylanxu.iteye.com/blog/1322066

http://zheng12tian.iteye.com/blog/1233638

http://www.cnblogs.com/aboutblank/p/3631453.html

http://www.importnew.com/14958.html

https://software.intel.com/zh-cn/blogs/2011/12/16/java-sleepwait

http://www.jasongj.com/java/multi_thread/

http://blog.csdn.net/nyistzp/article/details/12878417