线程学习二:Thread类常用方法

 在正式学习Thread类中的具体方法之前,我们先来了解一下线程有哪些状态,这个将会有助于后面对Thread类中的方法的理解。

  线程从创建到最终的消亡,要经历若干个状态。一般来说,线程包括以下这几个状态:创建(new)、就绪(runnable)、运行(running)、阻塞(blocked)、time waiting、waiting、消亡(dead)。

  当需要新起一个线程来执行某个子任务时,就创建了一个线程。但是线程创建之后,不会立即进入就绪状态,因为线程的运行需要一些条件(比如内存资源,在前面的JVM内存区域划分一篇博文中知道程序计数器、Java栈、本地方法栈都是线程私有的,所以需要为线程分配一定的内存空间),只有线程运行需要的所有条件满足了,才进入就绪状态。

  当线程进入就绪状态后,不代表立刻就能获取CPU执行时间,也许此时CPU正在执行其他的事情,因此它要等待。当得到CPU执行时间之后,线程便真正进入运行状态。

  线程在运行状态过程中,可能有多个原因导致当前线程不继续运行下去,比如用户主动让线程睡眠(睡眠一定的时间之后再重新执行)、用户主动让线程等待,或者被同步块给阻塞,此时就对应着多个状态:time waiting(睡眠或等待一定的事件)、waiting(等待被唤醒)、blocked(阻塞)。

  当由于突然中断或者子任务执行完毕,线程就会被消亡。

  下面这副图描述了线程从创建到消亡之间的状态:

  在有些教程上将blocked、waiting、time waiting统称为阻塞状态,这个也是可以的,只不过这里我想将线程的状态和Java中的方法调用联系起来,所以将waiting和time waiting两个状态分离出来。

常用方法

1、start

start()用来启动一个线程,当调用start方法后,系统才会开启一个新的线程来执行用户定义的子任务,在这个过程中,会为相应的线程分配需要的资源。

2、run

  run()方法是不需要用户来调用的,当通过start方法启动一个线程之后,当线程获得了CPU执行时间,便进入run方法体去执行具体的任务。注意,继承Thread类必须重写run方法,在run方法中定义具体要执行的任务。

3、yield

yield()方法详单与线程调度器,执行该方法后当前线程将交出其CPU使用权限,让别的线程有机会使用CPU。

  实际上,yield()方法对应了如下操作;先检测当前是否有相同优先级的线程处于同可运行状态,如有,则把CPU的占有权交给次线程,否则继续运行原来的线程,所以yield()方法称为“退让”,它把运行机会让给了同等级的其他线程。

 1 public class MainThreadTest implements Runnable {
 2 
 3     public static void main(String[] args) {
 4         Thread aa = new Thread(new MainThreadTest());
 5         Thread bb = new Thread(new MainThreadTest());
 6         aa.start();
 7         bb.start();
 8     }
 9 
10     @Override
11     public void run() {
12         for (int i = 0; i < 100; i++) {
13             System.out.println(Thread.currentThread().getName() + i);
14             Thread.yield();
15         }
16     }
17 }

  4、sleep

  调用sleep(long millis)将任务终止mills毫秒

 1 public class ThreadTest implements Runnable {
 2     private int count = 300;
 3 
 4     @Override
 5     public void run() {
 6         for (int i = 0; i < 100; i++) {
 7             System.out.println(Thread.currentThread().getName() + "........" + count--);
 8             try {
 9                 Thread.sleep(1000);
10             } catch (InterruptedException e) {
11                 // TODO Auto-generated catch block
12                 e.printStackTrace();
13             }
14         }
15     }
16 
17     public static void main(String[] args) {
18         ThreadTest aa = new ThreadTest();
19         Thread t1 = new Thread(aa);
20         Thread t2 = new Thread(aa);
21         Thread t3 = new Thread(aa);
22         t1.start();
23         t2.start();
24         t3.start();
25 
26     }
27     
28 }

带同步锁调用sleep()方法时

 1 public class MainThreadTest implements Runnable {
 2     private Object object = new Object();
 3 
 4     public static void main(String[] args) throws InterruptedException {
 5         MainThreadTest mtt = new MainThreadTest();
 6         Thread aa = new Thread(mtt);
 7         Thread bb = new Thread(mtt);
 8         aa.start();
 9         bb.start();
10     }
11 
12     @Override
13     public void run() {
14         synchronized (object) {
15             System.out.println(Thread.currentThread().getName() + "进入随眠状态");
16             try {
17                 Thread.sleep(1000);
18             } catch (InterruptedException e) {
19                 e.printStackTrace();
20             }
21             System.out.println(Thread.currentThread().getName() + "结束随眠状态");
22         }
23     }
24 }

  5、getPriority和setPriority

  用来查看和设置线程的优先级,优先级为1到10,默认为5,优先级越大占有CPU时间越久(相对于优先级第的而言,并不是绝对的)

 1 public class ThreadExtendsTest extends Thread { 
 2     public int priority;
 3 
 4     public ThreadExtendsTest(int priority) {
 5         super();
 6         this.priority = priority;
 7     }
 8 
 9     @Override
10     public void run() {
11         Thread.currentThread().setPriority(priority);
12         System.out.println(Thread.currentThread().getName() + Thread.currentThread().getPriority());
13         for (int i = 0; i < 100; i++) {
14             System.out.println(this.getName() + "..." + i);
15 
16         }
17     }
18 
19     public static void main(String[] args) {
20         ThreadExtendsTest aa = new ThreadExtendsTest(Thread.MIN_PRIORITY);
21         ThreadExtendsTest bb = new ThreadExtendsTest(Thread.MAX_PRIORITY);
22         aa.start();
23         bb.start();
24     }
25 
26 }

  注意:getPriority和setPriority都有final修饰,是关于线程的属性,调用这两个方法时需要先调用currentThread()方法,类似的还有getId、getName、setName等方法。

  6、jion

  Join()方法把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。

 1 public class MainThreadTest implements Runnable {
 2 
 3     public static void main(String[] args) throws InterruptedException{
 4         Thread aa = new Thread(new MainThreadTest());
 5         aa.start();
 6         for (int i = 0; i < 100; i++) {
 7             System.out.println(Thread.currentThread().getName() + i);
 8             aa.join();
 9         }
10     }
11 
12     @Override
13     public void run() {
14         for (int i = 0; i < 100; i++) {
15             System.out.println(Thread.currentThread().getName() + i);
16         }
17     }
18 }

7.interrupt

  Thread.interrupt()方法不会中断一个正在运行的线程。它的作用是,在线程受到阻塞时抛出一个中断信号,这样线程就得以退出阻塞的状态。更确切的说,如果线程被Object.wait, Thread.join和Thread.sleep三种方法之一阻塞,那么,它将接收到一个中断异常(InterruptedException),从而提早地终结被阻塞状态。

 

在上面已经说到了Thread类中的大部分方法,那么Thread类中的方法调用到底会引起线程状态发生怎样的变化呢?如图所示:

 

参考资料:

  《Java编程思想》

      http://www.cnblogs.com/dolphin0520/

  http://zy19982004.iteye.com/blog/1626916

  http://www.cnblogs.com/DreamSea/archive/2012/01/11/JavaThread.html#navigation

  http://www.blogjava.net/vincent/archive/2008/08/23/223912.html

  http://iteye.blog.163.com/blog/static/1863080962012111424544215/

  http://blog.csdn.net/lifei128/article/details/20363257

 

 

posted @ 2016-09-22 11:34  夜晚风吻尽  阅读(210)  评论(0编辑  收藏  举报