• Android(java)学习笔记4:线程的控制


    1. 线程休眠

    Java中线程休眠指让正在运行的线程暂停执行一段时间,进入阻塞状态,通过调用Thread类的静态方法sleep得以实现。

    当线程调用sleep进入阻塞状态后,在其休眠的时间内,该线程不会获得执行的机会,即使系统中没有其他可运行的线程,处于休眠中的线程也不会执行,常用sleep方法来暂停程序的执行

    1 线程休眠的sleep()方法的语法格式:
    2 try {
    3   Thread.sleep (2000);
    4 } catch (InterruptedException  e)  {
    5    e.printStackTrace();
    6 }

    下面我们根据具体的实例来了解sleep()的用法:

    当然这里是利用自己新建一个新的类ThreadSleep,也可以利用匿名类

     1 package cn.itcast_04;
     2 
     3 import java.util.Date;
     4 
     5 public class ThreadSleep extends Thread {
     6     @Override
     7     public void run() {
     8         for (int x = 0; x < 100; x++) {
     9             System.out.println(getName() + ":" + x + ",日期:" + new Date());
    10             // 睡眠
    11             // 困了,我稍微休息1秒钟
    12             try {
    13                 Thread.sleep(1000);
    14             } catch (InterruptedException e) {
    15                 e.printStackTrace();
    16             }
    17         }
    18     }
    19 }

    下面我们新建的一个ThreadSleepDemo类,调用main方法测试上面这个类:

     1 package cn.itcast_04;
     2 
     3 /*
     4  * 线程休眠
     5  *        public static void sleep(long millis)
     6  */
     7 public class ThreadSleepDemo {
     8     public static void main(String[] args) {
     9         ThreadSleep ts1 = new ThreadSleep();
    10         ThreadSleep ts2 = new ThreadSleep();
    11         ThreadSleep ts3 = new ThreadSleep();
    12 
    13         ts1.setName("林青霞");
    14         ts2.setName("林志玲");
    15         ts3.setName("林志颖");
    16 
    17         ts1.start();
    18         ts2.start();
    19         ts3.start();
    20     }
    21 }

    程序运行得出结果:

    2. 线程的挂起

    线程的挂起是指暂停当前正在执行的线程,当另一个线程执行完毕后,才继续执行当前线程(类似于单片机程序中的中断)。实现线程的挂起,可以使用Thread类中的join方法来完成。这就好比此时你正在看电视,却突然有人上门收水费,读者必须付完水费后才能继续看电视。

    当在某个程序执行流中调用其他线程的join()方法时候,调用线程将被阻塞,直到被join方法加入的join线程执行完毕为止。比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。

    join()方法通常由使用线程的程序调用,将大问题划分为许多小问题每个小问题分配一个线程。当所有的小问题都得到处理之后,再调用主线程来进一步操作

    下面是使用join()方法的实例:

     1 package cn.itcast_04;
     2 
     3 public class ThreadJoin extends Thread {
     4     @Override
     5     public void run() {
     6         for (int x = 0; x < 100; x++) {
     7             System.out.println(getName() + ":" + x);
     8         }
     9     }
    10 }

     测试类如下:

     1 package cn.itcast_04;
     2 
     3 /*
     4  * public final void join():等待该线程终止。 
     5  */
     6 public class ThreadJoinDemo {
     7     public static void main(String[] args) {
     8         ThreadJoin tj1 = new ThreadJoin();
     9         ThreadJoin tj2 = new ThreadJoin();
    10         ThreadJoin tj3 = new ThreadJoin();
    11 
    12         tj1.setName("李渊");
    13         tj2.setName("李世民");
    14         tj3.setName("李元霸");
    15 
    16         tj1.start();
    17         try {
    18             tj1.join();
    19         } catch (InterruptedException e) {
    20             e.printStackTrace();
    21         }
    22         
    23         tj2.start();
    24         tj3.start();
    25     }
    26 }

    执行结果:等"李渊"这个线程走完了,其余两个才会开始抢。

    首先是Main线程中使用join方法调用tj1线程,此时就会先执行tj1线程当tj1执行完了,再去让tj2 和 tj3 去抢CPU执行权

     

    下面看看JDK中join方法源码,如下:

     1 /** 
     2      *  Waits at most <code>millis</code> milliseconds for this thread to   
     3      * die. A timeout of <code>0</code> means to wait forever.   
     4      */  
     5     //此处A timeout of 0 means to wait forever 字面意思是永远等待,其实是等到t结束后。  
     6     public final synchronized void join(long millis)    throws InterruptedException {  
     7         long base = System.currentTimeMillis();  
     8         long now = 0;  
     9   
    10         if (millis < 0) {  
    11             throw new IllegalArgumentException("timeout value is negative");  
    12         }  
    13           
    14         if (millis == 0) {  
    15             while (isAlive()) {  
    16                 wait(0);  
    17             }  
    18         } else {  
    19             while (isAlive()) {  
    20                 long delay = millis - now;  
    21                 if (delay <= 0) {  
    22                     break;  
    23                 }  
    24                 wait(delay);  
    25                 now = System.currentTimeMillis() - base;  
    26             }  
    27         }  
    28     }  

      join方法实现是通过wait(小提示:Object 提供的方法)。 当main线程调用t.join时候,main线程会获得线程对象t的锁(wait 意味着拿到该对象的锁),调用该对象的wait(等待时间),直到该对象唤醒main线程 ,比如退出后。这就意味着main 线程调用t.join时,必须能够拿到线程t对象的锁。

    接下来我们看看下面代码,如下:

    public class JoinTest implements Runnable{  
          
        public static int a = 0;  
      
        public void run() {  
            for (int k = 0; k < 5; k++) {  
                a = a + 1;  
            }  
        }  
      
        public static void main(String[] args) throws Exception {  
            Runnable r = new JoinTest();  
            Thread t = new Thread(r);  
            t.start();        
            System.out.println(a);  
        }         
    }  

    输出结果,如下:

    请问程序的输出结果是 5 吗?

    答案是:有可能。其实你很难遇到输出5的时候,通常情况下都不是5。(上面输出结果就是0,不是5)当然这也和机器有严重的关系。

    为什么呢?

    我的解释是当主线程main方法执行System.out.println(a);这条语句时,线程还没有真正开始运行,或许正在为它分配资源准备运行

    因为为线程分配资源需要时间,而main方法执行完t.start()方法后继续往下执行System.out.println(a);

    这个时候得到的结果是a还没有被 改变的值0 。怎样才能让输出结果为5!其实很简单,join() 方法提供了这种功能。join() 方法,它能够使调用该方法的线程在此之前执行完毕。

    根据上面修改代码,如下:

     1 package com.himi.join;
     2 
     3 public class JoinTest implements Runnable {
     4 
     5      public static int a = 0;  
     6       
     7         public void run() {  
     8             for (int k = 0; k < 5; k++) {  
     9                 a = a + 1;  
    10             }  
    11         }  
    12       
    13         public static void main(String[] args) throws Exception {  
    14             Runnable r = new JoinTest();  
    15             Thread t = new Thread(r);  
    16             t.start();    
    17             //加入join()方法
    18             t.join();
    19             System.out.println(a);  
    20         }         
    21 
    22 }

    运行效果,如下:

    3. 线程的礼让:

        线程礼让就是给当前正在处于运行状态下的线程一个提醒,告知它可以将资源礼让给其他线程,这仅仅是一种暗示,没有任何一种机制保证当前的线程会将资源礼让。

    代码案例:

     1 package cn.itcast_04;
     2 
     3 public class ThreadYield extends Thread {
     4     @Override
     5     public void run() {
     6         for (int x = 0; x < 100; x++) {
     7             System.out.println(getName() + ":" + x);
     8             Thread.yield();
     9         }
    10     }
    11 }

    测试类的代码:

     1 package cn.itcast_04;
     2 
     3 /*
     4  * public static void yield():暂停当前正在执行的线程对象,并执行其他线程。 
     5  * 让多个线程的执行更和谐,但是不能靠它保证一人一次。
     6  */
     7 public class ThreadYieldDemo {
     8     public static void main(String[] args) {
     9         ThreadYield ty1 = new ThreadYield();
    10         ThreadYield ty2 = new ThreadYield();
    11 
    12         ty1.setName("林青霞");
    13         ty2.setName("刘意");
    14 
    15         ty1.start();
    16         ty2.start();
    17     }
    18 }

    运行结果如下:

    4. 守护线程(后台):

    代码示例如下:

     1 package cn.itcast_04;
     2 
     3 public class ThreadDaemon extends Thread {
     4     @Override
     5     public void run() {
     6         for (int x = 0; x < 100; x++) {
     7             System.out.println(getName() + ":" + x);
     8         }
     9     }
    10 }

    测试代码如下:

     1 package cn.itcast_04;
     2 
     3 /*
     4  * public final void setDaemon(boolean on):将该线程标记为守护线程或用户线程。
     5  * 当正在运行的线程都是守护线程时,Java 虚拟机退出。 该方法必须在启动线程前调用。 
     6  * 
     7  * 游戏:坦克大战。
     8  */
     9 public class ThreadDaemonDemo {
    10     public static void main(String[] args) {
    11         ThreadDaemon td1 = new ThreadDaemon();
    12         ThreadDaemon td2 = new ThreadDaemon();
    13 
    14         td1.setName("关羽");
    15         td2.setName("张飞");
    16 
    17         // 设置守护线程,表示一旦主线程main结束,这两个守护main线程的守护线程就要跟着结束
    18         td1.setDaemon(true);
    19         td2.setDaemon(true);
    20 
    21         td1.start();
    22         td2.start();
    23 
    24         Thread.currentThread().setName("刘备");
    25         for (int x = 0; x < 5; x++) {
    26             System.out.println(Thread.currentThread().getName() + ":" + x);
    27         }
    28     }
    29 }

    执行结果如下:

    线程"刘备"结束之后,其他两个线程也跑了一会再结束。(缓冲)

    可以根据经典坦克大战游戏类比学习:

    5. 线程的中断

     (1)代码演示:

     1 package cn.itcast_04;
     2 
     3 import java.util.Date;
     4 
     5 public class ThreadStop extends Thread {
     6     @Override
     7     public void run() {
     8         System.out.println("开始执行:" + new Date());
     9 
    10         // 我要休息10秒钟,亲,不要打扰我哦
    11         try {
    12             Thread.sleep(10000);
    13         } catch (InterruptedException e) {
    14             // e.printStackTrace();
    15             System.out.println("线程被终止了");
    16         }
    17 
    18         System.out.println("结束执行:" + new Date());
    19     }
    20 }
     1 package cn.itcast_04;
     2 
     3 /*
     4  * public final void stop():让线程停止,过时了,但是还可以使用。
     5  * public void interrupt():中断线程。 把线程的状态终止,并抛出一个InterruptedException。
     6  */
     7 public class ThreadStopDemo {
     8     public static void main(String[] args) {
     9         ThreadStop ts = new ThreadStop();
    10         ts.start();
    11 
    12         // 你超过三秒不醒过来,我就干死你
    13         try {
    14             Thread.sleep(3000);
    15             // ts.stop();
    16             ts.interrupt();
    17         } catch (InterruptedException e) {
    18             e.printStackTrace();
    19         }
    20     }
    21 }

    执行结果:休眠了3秒钟之后,这个ts线程就被杀死了,如下图中terminated

    图1:ts.stop()方法

    图2:ts.interrupt()方法

    (2)修改上面ThreadStopDemo的代码,ThreadStop不做修改,如下:

    ThreadStop:

     1 package cn.itcast_04;
     2 
     3 import java.util.Date;
     4 
     5 public class ThreadStop extends Thread {
     6     
     7     @Override
     8     public void run() {
     9         
    10         
    11         System.out.println("开始执行:"+new Date());
    12         //子线程休眠10s
    13         try {
    14             Thread.sleep(10000);
    15         } catch (InterruptedException e) {
    16             // TODO Auto-generated catch block
    17             //e.printStackTrace();
    18             System.out.println("线程被终止了");
    19         }
    20         
    21         System.out.println("结束执行:"+new Date());
    22     }
    23 
    24 }

    ThreadStopDemo,如下:

     1 package cn.itcast_04;
     2 
     3 public class ThreadStopDemo {
     4     
     5     public static void main(String[] args) {
     6         
     7         ThreadStop ts = new ThreadStop();
     8         
     9         ts.start();
    10         
    11         try {
    12             Thread.sleep(15000);
    13             ts.interrupt();
    14         } catch (InterruptedException e) {
    15             // TODO Auto-generated catch block
    16             e.printStackTrace();
    17         }
    18     }
    19 
    20 }

    运行程序,如下:

    (3)修改上面的ThreadStop,ThreadStopDemo,如下:

    ThreadStop,如下:

     1 package cn.itcast_04;
     2 
     3 import java.util.Date;
     4 
     5 public class ThreadStop extends Thread {
     6     
     7     @Override
     8     public void run() {
     9         
    10         
    11         System.out.println("开始执行:"+new Date());
    12         //子线程休眠16s
    13         try {
    14             Thread.sleep(16000);
    15         } catch (InterruptedException e) {
    16             // TODO Auto-generated catch block
    17             //e.printStackTrace();
    18             System.out.println("线程被终止了");
    19         }
    20         
    21         System.out.println("结束执行:"+new Date());
    22     }
    23 
    24 }

    ThreadStopDemo,如下:

     1 package cn.itcast_04;
     2 
     3 public class ThreadStopDemo {
     4     
     5     public static void main(String[] args) {
     6         
     7         ThreadStop ts = new ThreadStop();
     8         
     9         ts.start();
    10         
    11         try {
    12             Thread.sleep(15000);
    13             ts.interrupt();
    14         } catch (InterruptedException e) {
    15             // TODO Auto-generated catch block
    16             e.printStackTrace();
    17         }
    18     }
    19 
    20 }

    运行效果,如下:

  • 相关阅读:
    POJ 1754 Splay
    POJ 3481Double Queue Splay
    前缀表达式求值
    Treap(树堆):随机平衡二叉树实现
    Tarjian算法求强联通分量
    (转)priority_queue的用法
    001Angular2环境准备
    9.富客户端应用程序的线程
    8.信号
    7.线程的优先级
  • 原文地址:https://www.cnblogs.com/hebao0514/p/4507493.html
Copyright © 2020-2023  润新知