java并发编程基础(1)—线程之基本概念

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/txfyteen/article/details/52192045

java的多线程编程中涉及的东西比较多,本文主要从线程的概述、线程、进程与线程的区别、线程的状态以及切换

概述

1、线程是操作系统的概念,是进程的一个执行单元(通俗的讲就是进程的执行线路,一个进程至少有一个线程)。

2、在早期的操作系统中并没有线程的概念,进程是能拥有资源和独立运行的最小单位,也是程序执行的最小单位。任务调度采用的是时间片轮转的抢占式调度方式,而进程是任务调度的最小单位,每个进程有各自独立的一块内存,使得各个进程之间内存地址相互隔离。

3、后来,随着计算机的发展,对CPU的要求越来越高,进程之间的切换开销较大,已经无法满足越来越复杂的程序的要求了。于是就发明了线程,线程是程序执行中一个单一的顺序控制流程,是程序执行流的最小单元,是处理器调度和分派的基本单位。一个进程可以有一个或多个线程,各个线程之间共享程序的内存空间(也就是所在进程的内存空间)。一个标准的线程由线程ID、当前指令指针(PC)、寄存器和堆栈组成。而进程由内存空间(代码、数据、进程空间、打开的文件)和一个或多个线程组成。 —— [ 编程思想之多线程与多进程(1)——以操作系统的角度述说线程与进程 ]

为什么要引入线程:

提高系统的并发性,有效的使用系统的资源和提高系统的吞吐量(单位时间内执行的指令数)

进程和线程的区别

比较 线程 进程
调度 CPU调度和分配的基本单位 CPU资源分配的基本单位
并发性 进程与进程可以并发执行,进程下线程与线程也可以并发执行 进程与进程之间并发执行,若某进程服务被锁,便没有该进程的服务可提供服务了
系统开销 开销小(线程切换只需要保存少量的寄存器和内容,不涉及存储器管理方面,同一进程中,若线程有相同的地址空间,同步和通信容易,有的操作系统,同步和通信不需要系统内核干预) 开销大(旧CPU环境的保存和设置,新CPU环境的保存和设置)
拥有资源 线程不拥有系统资源,但是可以访问其隶属的进程资源。(也就是同一进程的代码段、数据段、以及系统资源可供同一进程的其他线程共享) 进程拥有系统资源的独立单位

进程与线程的关系图

这里写图片描述

线程间的状态

一、操作系统分析线程间的状态

这里写图片描述

                    线程的生命周期

创建:一个新的线程被创建,等待该线程被调用执行;
就绪:时间片已用完,此线程被强制暂停,等待下一个属于他的时间片到来;
运行:此线程正在执行,正在占用时间片;
阻塞:也叫等待状态,等待某一事件(如IO或另一个线程)执行完;
退出:一个线程完成任务或者其他终止条件发生,该线程终止进入退出状态,退出状态释放该线程所分配的资源。

二、从java分析线程间的状态(java1.5以后的源码):

/**
     * A thread state.  A thread can be in one of the following states:
     * <ul>
     * <li>{@link #NEW}<br>
     *     A thread that has not yet started is in this state.
     *     </li>
     * <li>{@link #RUNNABLE}<br>
     *     A thread executing in the Java virtual machine is in this state.
     *     </li>
     * <li>{@link #BLOCKED}<br>
     *     A thread that is blocked waiting for a monitor lock
     *     is in this state.
     *     </li>
     * <li>{@link #WAITING}<br>
     *     A thread that is waiting indefinitely for another thread to
     *     perform a particular action is in this state.
     *     </li>
     * <li>{@link #TIMED_WAITING}<br>
     *     A thread that is waiting for another thread to perform an action
     *     for up to a specified waiting time is in this state.
     *     </li>
     * <li>{@link #TERMINATED}<br>
     *     A thread that has exited is in this state.
     *     </li>
     * </ul>
     *
     * <p>
     * A thread can be in only one state at a given point in time.
     * These states are virtual machine states which do not reflect
     * any operating system thread states.
     *
     * @since   1.5
     * @see #getState
     */
    public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,
        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
        RUNNABLE,
        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
        BLOCKED,
        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * is waiting for a specified thread to terminate.
         */
        WAITING,
        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
        TIMED_WAITING,
        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
        TERMINATED;
    }
线程状态
(1)NEW(新建尚未运行/启动)
(2)RUNNABLE(处于可运行状态:正在运行或准备运行)
(3)BLOCKED(等待获取锁时进入的状态)
(4)WAITING(通过wait方法进入的等待)
(5)TIMED_WAITING(通过sleep或wait timeout方法进入的限期等待的状态)
(6)TERMINATED(线程终止状态)

(1)NEW(新建尚未运行/启动)
还没调用start,或者调用了start()方法,不一定立即改变线程状态,中间可能需要一些步骤才完成一个线程的启动。

    Thread t = new Thread();
    System.out.println(t.getState());//输出NEW

(2)RUNNABLE(处于可运行状态:正在运行或准备运行)
start调用结束,线程由NEW变成RUNNABLE,存活着,并尝试占用CPU资源,yield操作时,线程还是Runnable状态,只是它有一个细节的内部变化,做一个简单的让步。在Java层面是Runnable的状态,并不代表一定处于运行中的状态,比如BIO中,线程正阻塞在网络等待的时候,看到的状态依然是Runnable状态,而底层线程已经被阻塞住了。

Thread t = new Thread(){
            public void run(){
                for(int i=0; i< 10000; i++){
                    System. out.println(i);
               } 
           } 
       };
       t.start();
       System.out.println(t.getState());//输出RUNNABLE

(3)BLOCKED(两个线程,相互等待Synchronized)
线程被挂起了,原因通常是因为它在等待一个锁,当某个synchronized正好有线程在使用时,一个线程尝试进入这个临界区,就会被阻塞,直到另一个线程走完临界区或发生了相应锁对象的wait操作后,它才有机会去争夺进入临界区的权利。当抢到锁之后,才会从blocked状态恢复到runnable状态。这个状态它好像什么也不做一样。

final Object lock = new Object();
        Runnable run = new Runnable() {
              @Override
              public void run() {
                  synchronized (lock) {
                  for(int i=0; i<1000; i++){
                          System.out.println(Thread.currentThread().getName()+"=  "+i);
                    }
                  }
             }
         };
         Thread t1 = new Thread(run);
         t1.setName("t1");
         Thread t2 = new Thread(run);
         t2.setName("t2");

         t1.start();
         t2.start();
         System.out.println("t1"+t1.getState());
         System.out.println("t2"+t2.getState());

(4)WAITING(通过wait方法进入的等待)
当wait,join,park方法调用时,进入waiting状态。前提是这个线程已经拥有锁了。

final Object lock = new Object();
        Thread t1 = new Thread(){
             @Override
             public void run() {
                 int i = 0;
                 while(true ){
                      synchronized (lock) {
                          try {
                              lock.wait();   
                         } catch (InterruptedException e) {
                         }
                         System.out.println(i++);
                     }
                }
            }
        };

        Thread t2 = new Thread(){
             @Override
             public void run() {            
                 while(true ){
                      synchronized (lock) {
                          for(int i = 0; i< 100; i++){
                             System.out.println(i);
                         }
                         lock.notifyAll();
                     }
                }
            }
        };
        t1.setName( "^^t1^^");
        t2.setName( "^^t2^^");
        t1.start();
        t2.start();
        System.out.println("t1"+t1.getState());
        System.out.println("t2"+t2.getState());

线程进入waiting的三种方法:

调用Object.wait()且没有超时
调用Thread.join()且没有超时
调用LockSupport.park(Object)
Java千百问01基本概念(007)线程的状态有哪些

唤醒waiting线程的方法:
1、一个线程执行Object.wait()
2、另一个线程调用对象Object.notify()==唤醒一个处于wait线程
Object.notifyAll()==唤醒所有处于wait等待的线程。

blocked和waiting状态的区别是:
A、blocked是虚拟机认为程序还不能进入某个区域(临界区),它要求同一个时刻只能有一个线程进去,另外一个线程就处于blocked状态,blocked状态的线程正在等待获取锁。
B、发生wait等操作的先决条件是线程已经拿到锁,进入临界区,并且执行了一些事情,但执行某段程序时某些业务上的参数或者资源不满足,必须等待另外一个线程执行完后才满足,并唤醒该线程继续执行之后的代码。(也就是一个线程无限期的等待另外一个线程来唤醒)。
在waiting状态下,如果发生了interrupt操作,则处于该状态的线程在内部会抛出一个InterruptedException,这个异常应当在run方法内捕获,使得run方法正常地执行完成,当然捕获异常后,是决定让线程继续运行,还是结束等要根据业务场景才处理。

(5)TIMED_WAITING(通过sleep或wait timeout方法进入的限期等待的状态)
线程进入TIMED_WAITING的方法:

调用Thread.sleep()
调用Object.wait()超过时间阈值
调用Thread.join()超过时间阈值
调用LockSupport.parkNanos(Object,long)
调用LockSupport.parkUntil(Object,long)

当时间达到时触发线程回到工作状态Runnable。interrupt只对处于waiting或timed_waiting状态的线程起作用,对其他状态不起作用。这个仅需要在4的基础上, 在wait方法加上一个时间参数进行限制,把4中的synchronized 块改成如下就可以了.

synchronized (lock) {
   try {
      lock.wait(60 * 1000L);
   } catch (InterruptedException e) {
   }
   System.out.println(i++);
 }

(6)TERMINATED(线程终止状态)
线程结束了,就处于这种状态,也就是run方法运行完了。这只是Java语言级别的一种状态,在操作系统内部可能已经注销了相应的线程,或者将它复用给其他需要使用线程的请求。

        Thread t1 = new Thread();
        t1.start();
         try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
        }
        System.out.println(t1.getState());

线程间状态切换

Java线程的状态及切换

猜你喜欢

转载自blog.csdn.net/txfyteen/article/details/52192045