本篇是线程基础知识系列的第二篇,主要说下线程管理相关知识点。

线程基础知识系列(一)线程的创建和启动:说明了线程的2种创建和启动,join(),daemon线程,Callable
任务。

本文的主要内容

  1. 线程的状态

  2. 线程的优先级

  3. sleep vs wait

  4. 线程的流程控制

  5. Interrupt

  6. yield让出你的CPU



1.线程的状态

以《线程基础知识系列(一)线程的创建和启动》这张图,是程序的运行时线程信息截图。有main线程,user Threads,daemon Threads。现在咱们把重点放在线程状态上(RUNNING,WAIT,SLEEPING...)

线程的状态有哪些?状态转换图是怎么样的?

wKiom1dvlgej-_eRAABM-qR14cc719.png

线程状态转换图

wKiom1dv1sHRmhKcAAJRalKoBdc747.png


状态信息是枚举类型,线程状态分别是:New,RUNNABLE,BLOCKED,WAITING,TIMED_WAITED,TERMINATED.

wKiom1dv14iQKzEgAAI4CDOBw0U848.png

1.1 TimedWaitThreadDemo.java ,主要演示了TIMED_WAITING状态的触发时机

package com.threadexample.mgr;

import java.util.concurrent.TimeUnit;

/**
 * Created by Administrator on 2016/6/26.
 */
public class TimedWaitThreadDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread mythread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("begin sleep start");
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("end sleep start");
            }
        });

        mythread.start();
        TimeUnit.SECONDS.sleep(1);
        System.out.println("mythread.state:"+mythread.getState());
    }
}

执行结果

-----------------------

begin sleep start
mythread.state:TIMED_WAITING
end sleep start

--------------------------


1.2 WaitThreadDemo.java ,主要演示了WAITING状态的触发时机

package com.threadexample.mgr;

import java.util.concurrent.TimeUnit;

/**
 * Created by Administrator on 2016/6/26.
 */
public class WaitThreadDemo {
    private final static Object lock = new Object();
    public static void main(String[] args) throws InterruptedException {
        Thread mythread = new Thread(new Runnable() {
            @Override
            public void run() {
               synchronized (lock){
                   try {
                       lock.wait();
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
               }
            }
        });
        mythread.start();
        TimeUnit.SECONDS.sleep(1);//休眠1秒,保证能进入同步块
        System.out.println("mythread.state:"+mythread.getState());
    }
}

执行结果

----------------

mythread.state:WAITING

----------------

1.3BlockedThreadDemo.java,主要演示了BLOCKED状态的触发时机。需要涉及多个线程资源争用,所以需要多个线程。

package com.threadexample.mgr;

import java.util.concurrent.TimeUnit;

/**
 * Created by Administrator on 2016/6/26.
 */
public class BlockedThreadDemo {
    private final static Object lock = new Object();
    public static void main(String[] args) throws InterruptedException {
        Runnable ruunnble = new Runnable() {
            @Override
            public  void run() {
                synchronized (lock){
                    System.out.println(Thread.currentThread().getName()+"开始业务操作");
                    try {
                        TimeUnit.SECONDS.sleep(2);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"完成业务操作");
            }
            }
        };
        Thread mythread = new Thread(ruunnble);
        Thread mythread2 = new Thread(ruunnble);
        mythread.start();
        mythread2.start();
        System.out.println("mythread.state:" + mythread.getState());
        System.out.println("mythread2.state:"+mythread2.getState());
    }
}

执行结果

-------------------------

Thread-0开始业务操作
mythread.state:RUNNABLE
mythread2.state:BLOCKED
Thread-0完成业务操作
Thread-1开始业务操作
Thread-1完成业务操作

-------------------------

2.线程的优先级

线程有个优先级属性,优先级是从1到10的整数类型。

Thread Priority ConstantsInteger Value
MIN_PRIORITY1
NORM_PRIORITY5
MAX_PRIORITY10

理论上来说,优先级越高,获取CPU的的时间越大,这仅仅是概率问题,并不能保证优先级越高的线程一定先执行。线程的优先级,对于调度器而言,仅仅相当于一个提示器的作用,具体如何执行,还要看CPU的心情。

需要说明的事,依靠优先级的顺序来决定线程的执行顺序,是不靠谱的。线程的优先级是依靠操作系统底层调度的,由于操作系统的调度方式也存在差异,所以线程优先级的执行行为也会存在差异。

JAVA 提供了setPriority() 和getPriority()管理线程。

PriorityThreadDemo.java 演示了线程优先级的管理,通过分析结果也验证了,优先级并不能保证线程的执行顺序。

package com.threadexample.mgr;
import java.util.ArrayList;
import java.util.List;
public class PriorityThreadDemo {
    public static void main(String[] args) {
        Runnable ruunnble = new Runnable() {
            @Override
            public  void run() {
                System.out.println(Thread.currentThread().getName()+"\t优先级:"+Thread.currentThread().getPriority()+"\t执行完成");
            }
        };

        List<Thread> tasks = new ArrayList<Thread>();
        for(int i=Thread.MIN_PRIORITY;i<=Thread.MAX_PRIORITY;i++){
            Thread thread = new Thread(ruunnble);
            thread.setPriority(i);
            tasks.add(thread);
        }

        for(Thread thread:tasks){
            thread.start();
        }
    }
}

执行结果

--------------------

Thread-0    优先级:1    执行完成
Thread-4    优先级:5    执行完成
Thread-2    优先级:3    执行完成
Thread-1    优先级:2    执行完成
Thread-3    优先级:4    执行完成
Thread-5    优先级:6    执行完成
Thread-6    优先级:7    执行完成
Thread-8    优先级:9    执行完成
Thread-9    优先级:10    执行完成
Thread-7    优先级:8    执行完成

--------------------

3.sleep vs wait

sleep()和wait()方法,对线程的影响“当前线程停止执行”。但他们之间的存在本质区别

区别
wait
sleep
Class  belongs属于java.lang.Object class 属于java.lang.Thread class

Context

(上下文)

只能在Synchronized context
中调用。也就是常见的synchronized快中。
任意上下文
Locking (锁管理)
释放锁不释放锁

Wake up condition

唤醒条件

被另外线程,通过调用notify() or notifyAll() 唤醒
interrupt
和时间过期机制
Execution (执行时机)
线程间的通信
属于Thread的静态方法

4.线程的流程控制

SN


Methods with Description

1

暂停

public void suspend()

This method puts a thread in suspended state and can be resumed using resume() method.

2

停止

public void stop()

This method stops a thread completely.

3

恢复

public void resume()

This method resumes a thread which was suspended using suspend() method.

4

等待

public void wait()

Causes the current thread to wait until another thread invokes the notify().

5

唤醒

public void notify()

Wakes up a single thread that is waiting on this object's monitor.

遗憾的是suspend( ), resume( ), and stop( ) 这些方法都被弃用了,不建议使用。

ThreadControlDemo.java提供了暂停,恢复,停止的功能。有一点说明,必须保证状态信息的同步。

package com.threadexample.mgr;

class RunnableDemo implements Runnable {
    public Thread t;
    private String threadName;
    boolean suspended = false;

    RunnableDemo(String name) {
        threadName = name;
        System.out.println("Creating " + threadName);
    }

    public void run() {
        System.out.println("Running " + threadName);
        try {
            for (int i = 10; i > 0; i--) {
                System.out.println("Thread: " + threadName + ", " + i);
                // Let the thread sleep for a while.
                Thread.sleep(300);
                synchronized (this) {
                    while (suspended) {
                        wait();
                    }
                }
            }
        } catch (InterruptedException e) {
            System.out.println("Thread " + threadName + " interrupted.");
        }
        System.out.println("Thread " + threadName + " exiting.");
    }

    public void start() {
        System.out.println("Starting " + threadName);
        if (t == null) {
            t = new Thread(this, threadName);
            t.start();
        }
    }

    void suspend() {
        suspended = true;
    }

    synchronized void resume() {
        suspended = false;
        notify();
    }
}

public class ThreadControlDemo {
    public static void main(String args[]) {

        RunnableDemo R1 = new RunnableDemo("Thread-1");
        R1.start();

        RunnableDemo R2 = new RunnableDemo("Thread-2");
        R2.start();

        try {
            Thread.sleep(1000);
            R1.suspend();
            System.out.println("Suspending First Thread");
            Thread.sleep(1000);
            R1.resume();
            System.out.println("Resuming First Thread");
            R2.suspend();
            System.out.println("Suspending thread Two");
            Thread.sleep(1000);
            R2.resume();
            System.out.println("Resuming thread Two");
        } catch (InterruptedException e) {
            System.out.println("Main thread Interrupted");
        }

        try {
            System.out.println("Waiting for threads to finish.");
            R1.t.join();
            R2.t.join();
        } catch (InterruptedException e) {
            System.out.println("Main thread Interrupted");
        }
        System.out.println("Main thread exiting.");
    }
}

5.Interrupt

interrupt方法用于中断线程。调用该方法的线程的状态为将被置为"中断"状态。

注意:线程中断仅仅是置线程的中断状态位,不会停止线程。需要用户自己去监视线程的状态为并做处理。支持线程中断的方法(也就是线程中断后会抛出interruptedException的方法)就是在监视线程的中断状态,一旦线程的中断状态被置为“中断状态”,就会抛出中断异常。


InterruptDemo.java展示了Thread.interrupted()的使用。

package com.threadexample.mgr;

public class InterruptDemo {
    public static void main(String[] args) {
        System.out.println("#1:" + Thread.interrupted());

        // Now interrupt the main thread
        Thread.currentThread().interrupt();

        // Check if it has been interrupted
        System.out.println("#2:" + Thread.interrupted());

        // Check again if it has been interrupted
        System.out.println("#3:" + Thread.interrupted());
    }
}

执行结果

----------------------

#1:false
#2:true
#3:false

----------------------

分析结果得知,Thread.interrupted()会清理中断标记。

InterruptDemo2.java展示了isInterrupted()的使用。第一次调用和第二次调用返回结果一样。

package com.threadexample.mgr;
public class InterruptDemo2 {
    public static void main(String[] args) {
        Thread th1 = new Thread(new Runnable() {
            @Override
            public void run() {
                Thread currentThread = Thread.currentThread();
                currentThread.interrupt();
                System.out.println("isInterrupted()#1="+currentThread.isInterrupted());
                System.out.println("isInterrupted()#2="+currentThread.isInterrupted());
            }
        });
        th1.start();
    }
}

执行结果

----------------------

isInterrupted()#1=true
isInterrupted()#2=true

---------------------

isInterrupted()  VS interrupted()

方面
isInterrupted()interrupted()
不同点

Thread 静态方法。返回结果决定于当前线程的是否被中断。

该方法会清理线程的中断状态


Thread的实例方法。不会被清理。
相似点

public static boolean interrupted () {
     return currentThread().isInterrupted(true);
}


调用同一个方法,参数不同而已

private native boolean isInterrupted( boolean ClearInterrupted);

public boolean isInterrupted () {
     return isInterrupted( false);
}

6.yield ()放弃你的CPU

yield(),是一个影响调度器的hint,作用是临时放弃CPU资源,允许其他线程执行。

YieldDemo.java,展示了yield()的使用

package com.threadexample.mgr;

/**
 * Created by Administrator on 2016/6/26.
 */
public class YieldDemo implements Runnable {

    Thread t;

    YieldDemo(String str) {

        t = new Thread(this, str);
        // this will call run() function
        t.start();
    }

    public void run() {

        for (int i = 0; i < 5; i++) {
            // yields control to another thread every 5 iterations
            if ((i % 5) == 0) {
                System.out.println(Thread.currentThread().getName() + " yielding control...");
   /* causes the currently executing thread object to temporarily
   pause and allow other threads to execute */
                Thread.yield();
            }
        }

        System.out.println(Thread.currentThread().getName() + "  has finished executing.");
    }

    public static void main(String[] args) {
        new YieldDemo("Thread 1");
        new YieldDemo("Thread 2");
        new YieldDemo("Thread 3");
    }
}

结果

----------

Thread 1 yielding control...
Thread 3 yielding control...
Thread 2 yielding control...
Thread 3  has finished executing.
Thread 1  has finished executing.
Thread 2  has finished executing.

---------

但是执行了几次,结果一直在变化。yield根本不能保证执行顺序。

其他

Thread.setName()

Thread.isAlive()

ThreadGroup

Thread.activeCount()

资源

http://javahungry.blogspot.com/2015/11/5-difference-between-sleep-and-wait-with-example.html

http://www.tutorialspoint.com/java/java_thread_control.htm

http://www.java2s.com/Tutorials/Java/Java_Thread/0100__Java_Thread_Interrupt.htm