Android(java)学习笔记4:线程的控制
1. 线程休眠:
Java中线程休眠指让正在运行的线程暂停执行一段时间,进入阻塞状态,通过调用Thread类的静态方法sleep得以实现。
当线程调用sleep进入阻塞状态后,在其休眠的时间内,该线程不会获得执行的机会,即使系统中没有其他可运行的线程,处于休眠中的线程也不会执行,常用sleep方法来暂停程序的执行。
线程休眠的sleep()方法的语法格式:
try {
Thread.sleep (2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
下面我们根据具体的实例来了解sleep()的用法:
当然这里是利用自己新建一个新的类ThreadSleep,也可以利用匿名类:
 package cn.itcast_04;
 import java.util.Date;
 public class ThreadSleep extends Thread {
     @Override
     public void run() {
         for (int x = 0; x < 100; x++) {
             System.out.println(getName() + ":" + x + ",日期:" + new Date());
             // 睡眠
             // 困了,我稍微休息1秒钟
             try {
                 Thread.sleep(1000);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
     }
 }
下面我们新建的一个ThreadSleepDemo类,调用main方法测试上面这个类:
package cn.itcast_04; /*
* 线程休眠
* public static void sleep(long millis)
*/
public class ThreadSleepDemo {
public static void main(String[] args) {
ThreadSleep ts1 = new ThreadSleep();
ThreadSleep ts2 = new ThreadSleep();
ThreadSleep ts3 = new ThreadSleep(); ts1.setName("林青霞");
ts2.setName("林志玲");
ts3.setName("林志颖"); ts1.start();
ts2.start();
ts3.start();
}
}
程序运行得出结果:

2. 线程的挂起
线程的挂起是指暂停当前正在执行的线程,当另一个线程执行完毕后,才继续执行当前线程(类似于单片机程序中的中断)。实现线程的挂起,可以使用Thread类中的join方法来完成。这就好比此时你正在看电视,却突然有人上门收水费,读者必须付完水费后才能继续看电视。
当在某个程序执行流中调用其他线程的join()方法时候,调用线程将被阻塞,直到被join方法加入的join线程执行完毕为止。比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。
join()方法通常由使用线程的程序调用,将大问题划分为许多小问题,每个小问题分配一个线程。当所有的小问题都得到处理之后,再调用主线程来进一步操作。
下面是使用join()方法的实例:
 package cn.itcast_04;
 public class ThreadJoin extends Thread {
     @Override
     public void run() {
         for (int x = 0; x < 100; x++) {
             System.out.println(getName() + ":" + x);
         }
     }
 }
测试类如下:
package cn.itcast_04; /*
* public final void join():等待该线程终止。
*/
public class ThreadJoinDemo {
public static void main(String[] args) {
ThreadJoin tj1 = new ThreadJoin();
ThreadJoin tj2 = new ThreadJoin();
ThreadJoin tj3 = new ThreadJoin(); tj1.setName("李渊");
tj2.setName("李世民");
tj3.setName("李元霸"); tj1.start();
17 try {
tj1.join();
} catch (InterruptedException e) {
e.printStackTrace();
} tj2.start();
tj3.start();
}
}
执行结果:等"李渊"这个线程走完了,其余两个才会开始抢。
首先是Main线程中,使用join方法调用tj1线程,此时就会先执行tj1线程,当tj1执行完了,再去让tj2 和 tj3 去抢CPU执行权。

下面看看JDK中join方法源码,如下:
/**
* Waits at most <code>millis</code> milliseconds for this thread to
* die. A timeout of <code>0</code> means to wait forever.
*/
//此处A timeout of 0 means to wait forever 字面意思是永远等待,其实是等到t结束后。
public final synchronized void join(long millis) throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0; if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
} if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
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() 方法,它能够使调用该方法的线程在此之前执行完毕。
根据上面修改代码,如下:
 package com.himi.join;
 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();
             //加入join()方法
             t.join();
             System.out.println(a);
         }         
 }
运行效果,如下:

3. 线程的礼让:
线程礼让就是给当前正在处于运行状态下的线程一个提醒,告知它可以将资源礼让给其他线程,这仅仅是一种暗示,没有任何一种机制保证当前的线程会将资源礼让。
代码案例:
 package cn.itcast_04;
 public class ThreadYield extends Thread {
     @Override
     public void run() {
         for (int x = 0; x < 100; x++) {
             System.out.println(getName() + ":" + x);
             Thread.yield();
         }
     }
 }
测试类的代码:
package cn.itcast_04; /*
* public static void yield():暂停当前正在执行的线程对象,并执行其他线程。
* 让多个线程的执行更和谐,但是不能靠它保证一人一次。
*/
public class ThreadYieldDemo {
public static void main(String[] args) {
ThreadYield ty1 = new ThreadYield();
ThreadYield ty2 = new ThreadYield(); ty1.setName("林青霞");
ty2.setName("刘意"); ty1.start();
ty2.start();
}
}
运行结果如下:

4. 守护线程(后台):
代码示例如下:
 package cn.itcast_04;
 public class ThreadDaemon extends Thread {
     @Override
     public void run() {
         for (int x = 0; x < 100; x++) {
             System.out.println(getName() + ":" + x);
         }
     }
 }
测试代码如下:
package cn.itcast_04; /*
* public final void setDaemon(boolean on):将该线程标记为守护线程或用户线程。
* 当正在运行的线程都是守护线程时,Java 虚拟机退出。 该方法必须在启动线程前调用。
*
* 游戏:坦克大战。
*/
public class ThreadDaemonDemo {
public static void main(String[] args) {
ThreadDaemon td1 = new ThreadDaemon();
ThreadDaemon td2 = new ThreadDaemon(); td1.setName("关羽");
td2.setName("张飞"); // 设置守护线程,表示一旦主线程main结束,这两个守护main线程的守护线程就要跟着结束
td1.setDaemon(true);
td2.setDaemon(true); td1.start();
td2.start(); Thread.currentThread().setName("刘备");
for (int x = 0; x < 5; x++) {
System.out.println(Thread.currentThread().getName() + ":" + x);
}
}
}
执行结果如下:

线程"刘备"结束之后,其他两个线程也跑了一会再结束。(缓冲)
可以根据经典坦克大战游戏类比学习:

5. 线程的中断:
(1)代码演示:
 package cn.itcast_04;
 import java.util.Date;
 public class ThreadStop extends Thread {
     @Override
     public void run() {
         System.out.println("开始执行:" + new Date());
         // 我要休息10秒钟,亲,不要打扰我哦
         try {
             Thread.sleep(10000);
         } catch (InterruptedException e) {
             // e.printStackTrace();
             System.out.println("线程被终止了");
         }
         System.out.println("结束执行:" + new Date());
     }
 }
package cn.itcast_04; /*
* public final void stop():让线程停止,过时了,但是还可以使用。
* public void interrupt():中断线程。 把线程的状态终止,并抛出一个InterruptedException。
*/
public class ThreadStopDemo {
public static void main(String[] args) {
ThreadStop ts = new ThreadStop();
ts.start(); // 你超过三秒不醒过来,我就干死你
try {
Thread.sleep(3000);
// ts.stop();
ts.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
执行结果:休眠了3秒钟之后,这个ts线程就被杀死了,如下图中terminated
图1:ts.stop()方法

图2:ts.interrupt()方法

(2)修改上面ThreadStopDemo的代码,ThreadStop不做修改,如下:
ThreadStop:
 package cn.itcast_04;
 import java.util.Date;
 public class ThreadStop extends Thread {
     @Override
     public void run() {
         System.out.println("开始执行:"+new Date());
         //子线程休眠10s
         try {
             Thread.sleep(10000);
         } catch (InterruptedException e) {
             // TODO Auto-generated catch block
             //e.printStackTrace();
             System.out.println("线程被终止了");
         }
         System.out.println("结束执行:"+new Date());
     }
 }
ThreadStopDemo,如下:
 package cn.itcast_04;
 public class ThreadStopDemo {
     public static void main(String[] args) {
         ThreadStop ts = new ThreadStop();
         ts.start();
         try {
             Thread.sleep(15000);
             ts.interrupt();
         } catch (InterruptedException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         }
     }
 }
运行程序,如下:

(3)修改上面的ThreadStop,ThreadStopDemo,如下:
ThreadStop,如下:
 package cn.itcast_04;
 import java.util.Date;
 public class ThreadStop extends Thread {
     @Override
     public void run() {
         System.out.println("开始执行:"+new Date());
         //子线程休眠16s
         try {
             Thread.sleep(16000);
         } catch (InterruptedException e) {
             // TODO Auto-generated catch block
             //e.printStackTrace();
             System.out.println("线程被终止了");
         }
         System.out.println("结束执行:"+new Date());
     }
 }
ThreadStopDemo,如下:
 package cn.itcast_04;
 public class ThreadStopDemo {
     public static void main(String[] args) {
         ThreadStop ts = new ThreadStop();
         ts.start();
         try {
             Thread.sleep(15000);
             ts.interrupt();
         } catch (InterruptedException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         }
     }
 }
运行效果,如下:

Android(java)学习笔记4:线程的控制的更多相关文章
- java学习笔记15--多线程编程基础2
		本文地址:http://www.cnblogs.com/archimedes/p/java-study-note15.html,转载请注明源地址. 线程的生命周期 1.线程的生命周期 线程从产生到消亡 ... 
- java学习笔记14--多线程编程基础1
		本文地址:http://www.cnblogs.com/archimedes/p/java-study-note14.html,转载请注明源地址. 多线程编程基础 多进程 一个独立程序的每一次运行称为 ... 
- 0039 Java学习笔记-多线程-线程控制、线程组
		join线程 假如A线程要B线程去完成一项任务,在B线程完成返回之前,不进行下一步执行,那么就可以调用B线程的join()方法 join()方法的重载: join():等待不限时间 join(long ... 
- java学习笔记之线程(Thread)
		刚开始接触java多线程的时候,我觉得,应该像其他章节的内容一样,了解了生命周期.构造方法.方法.属性.使用的条件,就可以结束了,然而随着我的深入学习了解,我发现java的多线程是java的一个特别重 ... 
- 0040 Java学习笔记-多线程-线程run()方法中的异常
		run()与异常 不管是Threade还是Runnable的run()方法都没有定义抛出异常,也就是说一条线程内部发生的checked异常,必须也只能在内部用try-catch处理掉,不能往外抛,因为 ... 
- 【java学习笔记】线程
		1.线程的定义 ①继承Thread类,将执行的任务逻辑放到run方法中,调用start方法来开启线程 public class ThreadDemo { public static void main ... 
- Java学习笔记之——线程的生命周期、线程同步
		一. 线程的生命周期 新建(new Thrad):创建线程后,可以设置各个属性值,即启动前 设置 就绪(Runnable):已经启动,等待CPU调动 运行(Running):正在被CPU调度 阻塞(B ... 
- JAVA学习笔记16——线程的创建和启动
		Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例.每个线程的作用是完成一定的任务,实际上就是执行一段程序流(一段顺序执行的代码).Java使用线程执行体来代表这段 ... 
- 0041 Java学习笔记-多线程-线程池、ForkJoinPool、ThreadLocal
		什么是线程池 创建线程,因为涉及到跟操作系统交互,比较耗费资源.如果要创建大量的线程,而每个线程的生存期又很短,这时候就应该使用线程池了,就像数据库的连接池一样,预先开启一定数量的线程,有任务了就将任 ... 
- JAVA学习笔记16——线程生命周期
		当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态,在线程的生命周期中,它要经过新建(New).就绪(Runnable).运行(Running).阻塞(Blocking)和 ... 
随机推荐
- 通过Qt从URL下载文件
			示例1: 通过Qt自带的例子学习,位置:[安装盘符]:\Qt\Qt5.1.1\5.1.1\Src\qtbase\examples\network\download 示例2: 通过Qt的文档,位置: ... 
- oracle 基础知识(十五)----高水位线
			一,oracle的逻辑存储管理 ORACLE的逻辑存储管理,分4个粒度:表空间,段,区和块. ## 块 粒度最小的存储单位,现在标准的块大小是8K,ORACLE每一次I/O操作也是按块来操作的,也就是 ... 
- Tomcat服务器安装
			Tomcat服务器类似于XAMPP,主要安装步骤如下. 第一步: 安装JDK. 第二步: 安装tomcat. 第三步: 启动tomcat下bin下的startup.bat即可启动tomcat. 可能出 ... 
- Windows加密技术概述
			Windows加密是安全体系的重要基础和组成部分.现代CPU的保护模式是系统安全的硬件基石,基于CPU硬件的特权分级,Windows让自身的关键系统代码运行在高处理器特权级的内核模式,各种应用程序则运 ... 
- WCF入门教程通信(二)
			一.概述 WCF能够建立一个跨平台的安全.可信赖.事务性的解决方案,是一个WebService,.Net Remoting,Enterprise Service,WSE,MSMQ的并集,有一副很经典的 ... 
- jquery——write less,do more
			rite less, do more.这句话想必是很多语言都提倡的. 在此举三个jquery的应用体现 一.绑定多个事件类型 $("div").bind("mouseov ... 
- 04.Dictionary字典键值对集合
			Dictionary字典键值对集合和Hashtable键值对集合的功能非常类似, 只是在声明的时候,必须为其制定值的类型. 示例代码: namespace _11.Dictionary字典集合的学习 ... 
- Spring Chapter4 WebSocket 胡乱翻译 (一) 一个例子
			因为没有基础,不知道从哪里入手. 文档里的例子,https://github.com/rstoyanchev/spring-websocket-portfolio,这个除了WebSocket,还整了S ... 
- Fragment中的方法findFragmentById(int id)的返回值探讨
			在学习<Android编程权威指南>P124页的时候,遇到了这样的代码: 引起了我的疑问if的判断条件是(fragment==null),那执行完上一句 Fragment Fragment ... 
- 用于模式匹配的String方法和RegExp方法
			上一节总结了创建正则表达式的语法,这一篇笔者总结了用于模式匹配的String四个方法:search().replace().match().split()以及用于模式匹配的RegExp两个方法exec ... 
