陈公子的博客

java线程状态

java线程状态

java线程有以下几个状态

  • new 初始状态
  • runnable 运行状态(包括就绪和运行)
  • blocked 阻塞状态
  • waiting 等待状态,需要其他线程特定动作唤醒(通知或者中断)
  • time-waiting 超时等待状态,可以在指定时间内返回。
  • terminated 终止状态

    创建

    java构造线程有两种办法,Thread类和Runnable接口,Thread的类本身实现了Runnable接口。
    常见的作法,是通过thread类的public Thread(Runnable target)构造函数来创建线程。
    1
    2
    3
    4
    5
    6
    7
    8
    new Thread(new Runnable() {
    @Override
    public void run() {
    // TODO Auto-generated method stub
    }
    });
    thread类的初始话代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    private void init(ThreadGroup g, Runnable target, String name,
    long stackSize, AccessControlContext acc) {
    if (name == null) {
    throw new NullPointerException("name cannot be null");
    }
    this.name = name;
    Thread parent = currentThread();
    SecurityManager security = System.getSecurityManager();
    if (g == null) {
    if (security != null) {
    g = security.getThreadGroup();
    }
    if (g == null) {
    g = parent.getThreadGroup();
    }
    }
    g.checkAccess();
    if (security != null) {
    if (isCCLOverridden(getClass())) {
    security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
    }
    }
    g.addUnstarted();
    this.group = g;
    this.daemon = parent.isDaemon();
    this.priority = parent.getPriority();
    if (security == null || isCCLOverridden(parent.getClass()))
    this.contextClassLoader = parent.getContextClassLoader();
    else
    this.contextClassLoader = parent.contextClassLoader;
    this.inheritedAccessControlContext =
    acc != null ? acc : AccessController.getContext();
    this.target = target;
    setPriority(priority);
    if (parent.inheritableThreadLocals != null)
    this.inheritableThreadLocals =
    ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
    this.stackSize = stackSize;
    tid = nextThreadID();
    }
    从这段代码可以看出以下几点
  • 当前线程为创建线程的父线程
  • child线程继承parent的Daemon、优先级、和加载资源的contextClassLoader和一个可以继承的ThreadLocal。
    Daemon线程(后台线程)的finally块代码不会执行

    运行

    Thread类的start方法起来运行线程。底层通过调用navate方法来运行线程。
    start()方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码
    run()方法当作普通方法的方式调用,程序还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码

    阻塞

    线程执行到monitorenter保护的代码快时,会去获取monitorenter对应的对象锁,如未获取,则该线程进入同步队列,状态为阻塞。
    任意对象都拥有自己的monitor,包括class对象。

    等待/唤醒

    线程等待的方法主要有下面几种
  • object.wait() / object.wait(long)
  • object.join() / object.join(long)
  • lockSupport.park() / lockSupport.park(long)
    当线程调用某个对象的wati方法,进入等待。当另一个线程调用该对象的notify()/notifyall()方法,之前等待的线程唤醒。
    线程唤醒的方法注意下面几种
  • object.notify()/notifyAll()
  • lockSupport.unpark(Thread)
    调用对象wait或者notify方法的前题是获取当前对象的内置锁。
    通过wait/notify设计的经典作法
    等待方:
  • 获取对象锁
  • 条件检查
  • 为假则等待
  • 为真则执行后面的逻辑
    唤醒方:
  • 获取对象锁
  • 改变条件
  • 通知所有等待在对象的线程
    条件变量用volatile修饰来保证可见性

    终止

    线程对应的run方法运行完毕,则线程终止。不推荐使用stop来终止线程。可以通过状态变量来终止线程。
陈勋 wechat
欢迎扫码加入知识星球