java线程基本概念

Posted 清风徐徐而来

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java线程基本概念相关的知识,希望对你有一定的参考价值。

多线程是一个好东西,能够发挥多核cpu的魅力,也能更加好地构造程序,但是cpu是使用抢占式调度系统在某一个时刻都有可能会去切换其他的线程执行,因此学习多线程编程一定要了解到原子性代码执行之后就有可能是会被其他的线程给替换的。学习多线程必然需要了解清楚如下的多线程的状态。

1. join  底层使用wait和notify ,join是可以让一个线程执行之后再执行当前线程,是先让当前线程进行wait,然后执行完调用者的任务再唤醒。

2.yield 也就是一种让步机制,也就是把线程从运行时转到同步队列堵塞中(就绪状态)

3.wait 是一种堵塞的机制,是可以进行设置时间的,或者使用notify进行唤醒

4.notify 是一种唤醒机制

5.notifyall 

7.sleep 是一种堵塞的机制

8.interupt|interupted 是一种堵塞中断的机制

 

 

 

  注意:其中阻塞的情况分三种:

    (1)、等待阻塞:运行的线程执行wait()方法,该线程会释放占用的所有资源,JVM会把该线程放入“等待池”中。进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用notify()或notifyAll()方法才能被唤醒,

    (2)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入“锁池”中。

    (3)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

 

一、join

join()源码分析(基于JDK1.7.0_40)

复制代码
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;
        }
    }
}
复制代码

说明
从代码中,我们可以发现。当millis==0时,会进入while(isAlive())循环;即只要子线程是活的,主线程就不停的等待。
我们根据上面解释join()作用时的代码来理解join()的用法!
问题
虽然s.join()被调用的地方是发生在“Father主线程”中,但是s.join()是通过“子线程s”去调用的join()。那么,join()方法中的isAlive()应该是判断“子线程s”是不是Alive状态;对应的wait(0)也应该是“让子线程s”等待才对。但如果是这样的话,s.join()的作用怎么可能是“让主线程等待,直到子线程s完成为止”呢,应该是让"子线程等待才对(因为调用子线程对象s的wait方法嘛)"?
答案wait()的作用是让“当前线程”等待,而这里的“当前线程”是指当前在CPU上运行的线程。所以,虽然是调用子线程的wait()方法,但是它是通过“主线程”去调用的;所以,休眠的是主线程,而不是“子线程”!

二、线程中断机制 interupte

在线程中调用wait()、sleep()、join需要try catch interuptedException异常,

执行在其他线程中执行其他的线程的interupte()方法是把这个线程的中断标记设置为true,然后jvm会while监控中断,然后catch interuptedException 则会抛出异常,所以wait可以进行对异常的处理,然后在抛出异常的时候,会把中断标记设置为false继续执行,调用THread.interupted()方法会获得当前的中断值,并且把中断值设置为false。

 

如果不使用这些方法,是没有办法catch interuptedException异常的。

三、wait 和 sleep的理解

堵塞可以看成一个二个不同的等待队列

队列1 : sleep \\  io操作

队列2:  wait 

队列1 和 2 都是可以时间结束出队列到同步队列中,并且都可以使用中断机制结束堵塞。

队列2 是可以使用唤醒机制进行结束队列到锁队列,在锁队列中进行获得锁,然后才能到达同步队列(就绪状态)。

 四、wait notify 与 lock support park unpark的区别

wait notify 是必须在同步代码块进行堵塞和唤醒,强调的是一种同步的过程,同时也是针对于这个锁对象而言。

park unpark 是强调是阻塞和唤醒的本身的功能,是针对于Thread而言的,同时可以针对性进行唤醒。

一个强调同步、一个强调本身的功能。

park函数是将当前调用Thread阻塞,而unpark函数则是将指定线程Thread唤醒。

与Object类的wait/notify机制相比,park/unpark有两个优点:

  1. 以thread为操作对象更符合阻塞线程的直观定义
  2. 操作更精准,可以准确地唤醒某一个线程。

区别是:notify随机唤醒一个线程,notifyAll唤醒所有等待的线程,增加了灵活性

以上是关于java线程基本概念的主要内容,如果未能解决你的问题,请参考以下文章

多线程编程

09_1_线程的基本概念

java多线程之基本概念

Java - 线程基本概念

Java高级编程--多线程

多线程是啥