`

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从入门到精通:...

    Step by StepLinux C多线程编程入门(基本API及多线程.pdf

    Step by StepLinux C多线程编程入门(基本API及多线程.pdf

    Java-Threads-Step-By-Step

    Java线程循序渐进:概述 进程与线程 ################################################ ################################ 第1节-创建线程 ################################################ ####################...

    多线程下载技术论文.rar

    3.1 JAVA中的多线程与线程安全 6 3.1.1 Java中的多线程 6 3.1.2 Java中的线程安全 7 3.2 HTTP协议简介 8 3.3 断点续传原理 8 4 需求分析 10 4.1用户需求分析 10 4.2 业务流分析 11 5. 整体设计 11 5.1 系统...

    Java测试题2答案

    《Java测试题2》 &lt;br&gt;一、 选择 1.欲构造ArrayList类的一个实例,此类继承了List接口,下列哪个方法是正确的 ? B A ArrayList myList=new Object(); B List myList=new ArrayList(); C ...

    Android异步多线程加载图片

    // step one : initImageLoader(cacheDir,R.drawable.alert_dark_frame); // step two bindImage(key,url,imageView,extra); // download images in other way fit Adapter Mode (BaseAdapter,...

    Delphi使用MainThreadWake解决多线程输出同步实例

    摘要:Delphi源码,系统相关,线程实例  压缩包内含有两个示例,用于演示如何实现一个Delphi第三访的MainThreadWake...如果在该程序中,iMax值足够大,且step值足够小(或随机),那么就很容易导致控制台的争用(冲突)。  

    JNI技术手册 c/c++调用java

    2) 如何将java传入的String参数转换为c的char*,然后使用? 57 3) 将c中获取的一个char*的buffer传递给java? 57 4) 不知道占用多少空间的buffer,如何传递出去呢? 58 五、 对JAVA传入数据的处理 58 1) 如果传入的是...

    两个多线程小程序

    多线程 求质数 返回数组中的最大值 bool isPrime(long x) { if (x ) return false; if (x == 2) return true; for (long i = 2; i (sqrt((long double)x));i++) if (x%i == 0) return false; return true; } ...

    使用GDB调试多线程实例详解

    先写一段多线程程序。 makefile 加上 -g参数生成可调式信息, 可以进行调试。 pthread不是Linux下的默认的库,也就是在链接的时候,无法找到phread库中哥函数的入口地址,于是链接会失败。在gcc编译的时候,...

    Visual C#2010 从入门到精通(Visual.C#.2010.Step.By.Step).完整去密码锁定版 I部分

    原书名: Microsoft Visual C# 2010 Step by Step 原出版社: Microsoft Press 作者: (英)John Sharp 译者: 周靖 丛书名: 微软技术丛书 出版社:清华大学出版社 ISBN:9787302234289 上架时间:2010-9-6 ...

    Learn-Java-12-Programming:学习Java 12编程,由Packt发布

    探索多线程,异步,功能和React式编程 向您的应用程序添加用户友好的图形界面 找出什么是流以及它们如何在数据处理中提供帮助 了解微服务的重要性,并利用它们使您的应用程序健壮和可扩展 探索Java设计模式和最佳...

    delphi多线程超COOL示例

    step_mun: Integer; max_mun: Integer; FProgressBar: TProgressBar; FLabel: TLabel; procedure DoProgress; protected procedure Execute; override; public constructor Create(CreateSuspended: ...

    JAVA 实现《捕鱼达人》游戏-全部源码

    2、渔网的范围和鱼的范围重叠。——判断一个点是否在矩形范围之内即可。同理:打飞机的游戏也可以依照这种算法实现。 3、由于每条鱼的行为不一样,所以要继承线程类,实现并发——屏幕上有多条鱼各自移动。鱼池继承...

    step-daemon:步进式-用于3D打印的外部计划器和步进器

    步骤守护程序 Step Daemon(步进式)是用于3d打印机的外部计划程序,该计划... 多线程管道。 双立方床水准仪具有每步精度(相对于每行)。 兼容OctoPrint。 与对Marlin的直接步进块支持一起开发。 适用于Linux(包

    64位VEH调试器,从控制台获取用户输入的命令

    //查看所有线程: ~* 查看线程1的栈: ~1 查看线程所有信息包括堆栈: ~* -a //查看进程内存属性 lmm //查看句柄!handle 查看h1 !handle h1 , !handle rcx //查看窗口lwd //resume线程 ~1 m resume all线程: ~* m //...

    PageRank算法的C实现,有和没有并行化_C语言_代码_下载

    PageRank 算法的 C 实现,有和没有并行化 包括几个文件: ...自定义调度类型(静态、动态)和线程数; step2mmap.c ,与step2.c相同,但使用 mmap; step3mmap.c ,与step3.c相同,但使用 mmap。

    基于java的黑白棋桌面应用程序源码+项目说明(课设作业).zip

    其中LocalPlayer作为AIPlayer和HumanPlayer的装饰器,在内部保存这两个类之一的一个引用,在自身的singleStep方法中,调用被装饰类对象的singleStep方法,并添加向远程发送信息的装饰代码。 4. 设置棋盘不能够接受...

    GDB调试详细命令

    GDB详细手册,文档内部分内容: ...(gdb) thread apply ID1 ID2 command //让一个或多个线程执行GDB命令 (gdb) set scheduler-locking off|on|step //只有当前函数,当前线程执行 完整版本请下载该手册!

Global site tag (gtag.js) - Google Analytics