`

Java线程Step By Step(Step 2)

阅读更多

(See http://www.suneca.com/article.asp?id=54

四、Join方法的使用    
Thread API 包含了等待另一个线程完成的方法:join() 方法。当调用 Thread.join() 时,调用线程将阻塞,直到被join方法加入的目标线程完成为止。 可以于解起来抽象一睦,现在我们来举一个例子说明问题。
 程序代码
package zizz;

/**
* 使用继承方式的线程实现.
* 
* @author <a href="http://www.suneca.com">zizz</a>
*
* @Create-Time:2008 下午10:25:33
*/

public class MyThread extends Thread {
    
    public void run() {
        //循环输出1 到 100
        for(int i=1;i<=10;i++){
            System.out.println("子线程输出:" + i);
        }
    }
    
    public static void main(String[] args){
        //创建一个线程实例
        MyThread t1 = new MyThread();
        //线程进入运行态
        t1.start();
        //主线程输出
        System.out.println("主线程输出:http://www.suneca.com");
    }
}


输出结果为:


从结果我们可以看到,对于我们运行MyThread这个程序,在主线程当中创建一个新的子线程,新的子线程启动后,主线程输出博客地址。因为当前主线程处于运行态,而子线程是处于可运行态,所以输出的结果为先输出网址,再输出了线程输出的数据。但也有可能会出现这种情况,子线程进入可运行态之后,马上进入运行态,那此时的是输出子线程的数据,再输出主线程的数据,它们的执行完全是由线程调度器进行调度。我们再将程序做如下的修改:
 程序代码
package zizz;

/**
* 使用继承方式的线程实现.
* 
* @author <a href="http://www.suneca.com">zizz</a>
*
* @Create-Time:2008 下午10:25:33
*/

public class MyThread extends Thread {
    
    public void run() {
        //循环输出1 到 100
        for(int i=1;i<=100;i++){
            System.out.println("子线程输出:" + i);
        }
    }
    
    /**
     * 应用程序入口.
     * 
     * @param args
     */

    public static void main(String[] args){
        //创建一个线程实例
        MyThread t1 = new MyThread();
        //线程进入运行态
        t1.start();
        //主线程输出
        for(int i=0;i<100;i++){
            System.out.println("主线程输出:http://www.suneca.com");
        }
    }
}


此时的输出结果为:



主线程跟子线程在线程调度器的调度下,相互抢夺CPU资源,交叉运行着!

那么,如果我希望程序启用子线程,必须等待着子线程执行完毕之后,主线程才能继续执行下去,那该怎么办?那此时,我们就必须使用到join这个方法啦!当使用Thread.join()时,调用线程将阻塞。因为子线程是由主线程进行调用的,所以当子线程调用到join这个函数时,主线程将阻塞,必须等待子线程执行完毕之后,才能继续执行。使用join的程序:
 程序代码
package zizz;

/**
* 使用继承方式的线程实现.
* 
* @author <a href="http://www.suneca.com">zizz</a>
*
* @Create-Time:2008 下午10:25:33
*/

public class MyThread extends Thread {
    
    public void run() {
        //循环输出1 到 100
        for(int i=1;i<=10;i++){
            System.out.println("子线程输出:" + i);
        }
    }
    
    /**
     * 应用程序入口.
     * 
     * @param args
     */

    public static void main(String[] args){
        //创建一个线程实例
        MyThread t1 = new MyThread();
        //线程进入运行态
        t1.start();
        try {
            //线程的调用者,即主线程阻塞!
            t1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //主线程输出
        for(int i=0;i<10;i++){
            System.out.println("主线程输出:http://www.suneca.com");
        }
    }
}


输出结果为:



从结果当中,我们可以看出,当子线程调用到join的时候,主线程将阻塞,子线程执行完毕之后,主线程才能继续执行。对于join()方法,还有两个重载方法,比如joing(long millis),那就是让主程序阻塞多长时间后才能恢复到可运行状态。

如果主程序调用了两个子线程,那这两个子线程是如何工作的呢?
 程序代码
package zizz;

/**
* 使用继承方式的线程实现.
* 
* @author <a href="http://www.suneca.com">zizz</a>
*
* @Create-Time:2008 下午10:25:33
*/

public class MyThread extends Thread {
    
    public MyThread(String name){
        super(name);
    }
    
    public void run() {
        //循环输出1 到 100
        for(int i=1;i<=100;i++){
            System.out.println("子线程输出:" + this.getName() + " - " + i);
        }
    }
    
    /**
     * 应用程序入口.
     * 
     * @param args
     */

    public static void main(String[] args){
        //创建一个线程实例
        MyThread t1 = new MyThread("t1");
        MyThread t2 = new MyThread("t2");
        //线程进入运行态
        t1.start();
        t2.start();
        try {
            //线程的调用者,即主线程阻塞!
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //主线程输出
        for(int i=0;i<10;i++){
            System.out.println("主线程输出:http://www.suneca.com");
        }
    }
}


输出结果:



从图的输出结果我们可以看出:对于在线程t1跟线程t2当中都调用了线程的join()方法,那么,调用t1、t2的主线程将阻塞,等到t1、t2都执行完毕之后,再执行主线程。对于子线程t1跟t2,它们的一个先后顺序,如何进行调度,完全是由线程调度器进行管理!

五、多线程
从前面的例子我们已经可以看出,对于有两个以上的线程同时启动,那这些线程的执行的先后顺序我们是没有办法预知的,因为对于它们的调用完全是由线程调度器进行调用!当子线程t1跟t2同时处于运行状态,那谁先执行谁慢执行,由线程调度器决定。那我们程序能否进行控制呢?答案是可以的,我们可以通过设计优先级别来进行控制。每一个线程,默认的优先级别为5,值越高,表示优先级别越高(最高为10),值越低(最低为1),表示优先级别越低!当线先级别相等的时候,那就只有排队等待着线程调度器的调用。
 程序代码
package zizz;

/**
* 使用继承方式的线程实现.
* 
* @author <a href="http://www.suneca.com">zizz</a>
*
* @Create-Time:2008 下午10:25:33
*/

public class MyThread extends Thread {
    
    public MyThread(String name){
        super(name);
    }
    
    public void run() {
        //循环输出1 到 100
        for(int i=1;i<=10;i++){
            System.out.println("子线程输出:" + this.getName() + " - " + i);
        }
    }
    
    /**
     * 应用程序入口.
     * 
     * @param args
     */

    public static void main(String[] args){
        //创建一个线程实例
        MyThread t1 = new MyThread("t1");
        MyThread t2 = new MyThread("t2");
        
        //线程进入运行态
        t1.start();
        t2.start();
        //主线程输出  
        System.out.println("主线程输出:http://www.suneca.com");
        
    }
}


t1比t2先启动,进入可运行态,排队等候线程的调度。执行结果:



如果设置了线程的优先级,如:
 程序代码
package zizz;

/**
* 使用继承方式的线程实现.
* 
* @author <a href="http://www.suneca.com">zizz</a>
*
* @Create-Time:2008 下午10:25:33
*/

public class MyThread extends Thread {
    
    public MyThread(String name){
        super(name);
    }
    
    public void run() {
        //循环输出1 到 100
        for(int i=1;i<=10;i++){
            System.out.println("子线程输出:" + this.getName() + " - " + i);
        }
    }
    
    /**
     * 应用程序入口.
     * 
     * @param args
     */

    public static void main(String[] args){
        //创建一个线程实例
        MyThread t1 = new MyThread("t1");
        MyThread t2 = new MyThread("t2");
        
        //设置t1的的优先级别为最低
        t1.setPriority(Thread.MIN_PRIORITY);
        //设置t2的优先级别为最高
        t2.setPriority(Thread.MAX_PRIORITY);        
        
        //线程进入运行态
        t1.start();
        t2.start();
        //主线程输出  
        System.out.println("主线程输出:http://www.suneca.com");
        
    }
}


执行结果:

从结果当中我们可以看到,最早的时候是由主线程执行,主线程占用着CPU资源,接着,线程t1启动,线程t1进入排队,等候着线程调度器的调度;再接着,线程t2启动,线程t2也进入排队。
我们从结果当中更可以发现一点,对于高于5的线程优先级别,它更容易从当中正在执行的线程(主线程)当中抢夺CPU资源。

多线程的另外一种情况就是,多个线程共享同一个线程实例。
 程序代码
package zizz;

/**
* 使用实现Runnable接口的线程.
* 
* @author <a href='http://www.suneca.com'>ZIZZ</a>
*
* @Create-Time:2008 下午10:48:31
*/

public class MyRunnable implements Runnable{

    public void run() {
        for(int i=0;i<100;i++){
            System.out.println(Thread.currentThread().getName() + " : " + i);
        }
    }
    
    public static void main(String[] args){
        //构造一个Runnable的实例
        MyRunnable runnable = new MyRunnable();
        //创建新的线程
        Thread t1 = new Thread(runnable,"T1");
        Thread t2 = new Thread(runnable,"T2");
        
        //线程启动.
        t1.start();
        t2.start();
    }

}


执行结果片断:



当多线程共享同一个线程实例的时候,我们需要考虑一下线程的同步问题。
分享到:
评论

相关推荐

    Microsoft.Visual.C#.2010.Step.by.Step].(John.Sharp).中英文文字版

    《Visual C# 2010从入门到精通:Step by Step》以深受读者欢迎的“动手练习”(learn-by-doing exercise)风格,演示了如何、何时以及为何使用C认#快速应用程序开发环境的特性。通过《Visual C# 2010从入门到精通:...

    Assembly Language Step-by-Step

    ### 《Assembly Language Step-by-Step》知识点梳理 #### 一、书籍基本信息 - **书名**:《Assembly Language Step-by-Step》 - **作者**:Jeff Duntemann - **出版社**:Wiley Publishing, Inc. - **出版年份**:...

    Visual C# Step by Step (中文版)+附带源码包

    《Visual C# Step by Step (中文版)》是一本针对初学者至中级程序员设计的教程,旨在帮助读者全面掌握Visual C#编程语言。这本书详细介绍了如何使用Microsoft的Visual Studio开发环境,尤其是针对C#语言的功能和特性...

    Assembly Language Step-By-Step - (Wiley, 2009, 0470497025).pdf

    《Assembly Language Step-by-Step: Programming with Linux》(第三版)是一本深入讲解汇编语言及其在Linux环境下的应用的专业书籍。本书由Jeff Duntemann编写,并于2009年由Wiley出版社出版。该书不仅适合初学者...

    C# Step By Step 2010

    《C# Step By Step 2010》是一本针对初学者至中级程序员的C#编程教程,通过逐步学习的方式,全面介绍了Visual C# 2010的使用技巧和核心概念。这本书覆盖了从基础语法到高级特性的广泛主题,旨在帮助读者深入理解和...

    Microsoft Visual C# 2008 Step by step 源码及书

    《Microsoft Visual C# 2008 Step by Step》是一本专为初学者设计的C#编程教程,它深入浅出地介绍了C#语言的基础知识和.NET Framework的应用。这本书不仅涵盖了编程的基本概念,还提供了丰富的实例,使得学习者能够...

    ASP.NET 4.0Step.by.Step

    《ASP.NET 4.0 Step by Step》是一本由George Shepherd撰写的书籍,由Microsoft Press出版。本书详细介绍了最新的ASP.NET 4.0技术,并通过一系列循序渐进的教程帮助读者深入理解并掌握该技术。对于想要学习或提升ASP...

    VxWorks调试 step by step

    本文将基于提供的标题“VxWorks调试 step by step”以及描述,深入探讨VxWorks调试的过程,并结合可能包含的文档资源,如“打通VxWorks调试环境 Step by Step.doc”和“20087108422323967.pdf”,提供详尽的知识点...

    Visual C# 2010 Step By Step源码

    《Visual C# 2010 Step By Step》是一本深受程序员喜爱的教程书籍,它详细介绍了Microsoft的C#编程语言在2010版本中的使用。这本书通过一系列的实践步骤,帮助读者从零基础逐步掌握C#编程,涵盖了语言基础、面向对象...

    Java-step:一些java的东西

    7. **多线程**:Java内置对多线程的支持,Thread类和Runnable接口允许开发人员创建并发执行的任务,提高程序的效率。 8. **Swing和JavaFX**:这两个是Java的图形用户界面(GUI)库,用于构建桌面应用。Swing是老...

    VC.NET_Step_by_Step.zip_step by step

    《VC++.NET Step by Step》是一本针对微软的Visual C++ .NET编程环境的逐步学习指南。这本书通过一系列章节,详细介绍了如何使用这个强大的开发工具进行应用程序开发。压缩包中的文件名代表了书籍的不同章节,这表明...

    Microsoft Visual Basic 2008 Step by Step

    从给定的文件信息来看,我们讨论的主题是“Microsoft Visual Basic 2008 Step by Step”,这是一本由Michael Halvorson编写的书籍,由Microsoft Press出版,于2008年发行。本书旨在为读者提供逐步学习Visual Basic ...

    visual csharp 2010 step by step (从入门到精通)源码

    《Visual C# 2010 Step by Step》是一本专为初学者和有经验的开发者设计的教程,旨在帮助读者全面掌握C#编程语言及其在.NET Framework 4.0环境下的应用。这本书通过逐步指导的方式,深入浅出地讲解了C# 2010的各种...

    VC.net_Step_by_Step.rar_VC控制_step by step_vc.net MFC

    《VC++.net_Step_by_Step.rar》是一个深入学习Visual C++.net的教程资源,它旨在引导初学者从基础的控制台程序开发逐渐过渡到更高级的Windows SDK控制编程,最终掌握MFC(Microsoft Foundation Classes)框架的应用...

    Visual C# 2010 Step By Step 随书代码

    《Visual C# 2010 Step By Step》是一本专为初学者和有一定编程基础的读者设计的教程书籍,其随书代码是学习过程中的重要辅助资源。这本书旨在通过逐步指导的方式,帮助读者深入理解和掌握Visual C# 2010这门编程...

    vb教程 step by step

    VB教程Step by Step是针对初学者的一套详细指导,旨在帮助读者逐步掌握Visual Basic (VB)编程语言。VBScript虽然在名称中提及,但这里主要讨论的是VB,它是一种基于事件驱动的编程语言,广泛应用于Windows应用程序...

    Microsoft.Visual.Basic.2010.Step.by.Step

    ### Microsoft Visual Basic 2010 Step by Step #### 知识点概览 - **基础知识**:介绍Visual Basic 2010的基础概念、安装配置及开发环境。 - **编程基础**:涵盖变量、数据类型、流程控制(条件语句、循环)、函数...

Global site tag (gtag.js) - Google Analytics