• java多线程(二)-Runnable和Thread


    Java在顺序性语言的基础上提供了多线程的支持。Java的线程机制是抢占式的。这表示调度机制会周期的中断线程,将上下文切换到另一个线程,从而为每个线程都提供时间片。(与抢占式多线程对应的是 协作式多线程,每个子线程都自动的放弃控制,这就要求程序员需要在子线程的代码中插入某些让步语句)。

    Java的多线程,最常见的是 Runnable和Thread类。

    示例代码:src/thread_runnable/CountDown.java

     1 public  class CountDown implements Runnable{
     2     protected int countDown = 5;
     3     private static int myId= 0;
     4     private final int taskId = myId++;
     5     public CountDown() {
     6         super();
     7     }
     8 
     9     
    10     public CountDown(int countDown) {
    11         super();
    12         this.countDown = countDown;
    13     }
    14     
    15     public String status() {
    16         return  "#" + taskId + "#(" + (countDown>0 ? countDown : "Over") + "),  " + Thread.currentThread().getName();
    17     }
    18     public void run() {
    19             while(countDown-- > 0){
    20                 System.out.println(status());
    21                 Thread.yield();
    22             }
    23     }
    24     

    输出结果:

    通过输出可以看出来,Runnable的运行其实还是main线程。(当一个java程序运行时,默认会启动两个线程,一个main线程,一个gc线程)。
    所以说,Runnable接口其实就是 描述任务的接口,要想定义某个任务,可以 实现Runnable接口并编写run()方法。
    另外,代码当中的 Thread.yield() 方法是对线程调度器的一种建议。意思是“当前线程最重要的部分已经执行完毕了,可以把时间片切换给其他线程了”。当然,该方法也就是个建议而已,实际效果这个取决于具体的jvm。就像你跟领导提意见一样,建议可以提,但是领导是否采纳那就另一说了。因为java的线程机制是抢占式机制。

    而实际上,真正实现启动新线程的是 Thread类,
    示例代码:src/thread_runnable/DirectThread.java

     1 public class DirectThread extends Thread{
     2     protected int countDown = 5;
     3     
     4     public String status() {
     5         return  "###(" + (countDown>0 ? countDown : "Over") + "),  " + Thread.currentThread().getName();
     6     }
     7     @Override
     8     public void run() {
     9         // TODO Auto-generated method stub
    10         while(countDown-- > 0){
    11             System.out.println(status());
    12         }
    13     }
    14 
    15     public static void main(String[] args) {
    16         System.out.println("DirectThread --- main start, " + Thread.currentThread().getName());
    17         new DirectThread().start();
    18         System.out.println("DirectThread --- main end, " + Thread.currentThread().getName());
    19     }
    20 }

    输出结果:

    通过代码和输出结果,我们可以观察到Thread类,的确启动了一个新线程,并且可以看到main函数方法最后一条语句执行完,才开始输出Thread类中 run()方法当中的内容。这个run()方法就是新线程需要执行的任务。

    不过在实际当中,我们经常并不是单独使用Thread类,而是在Thread类的构造器中传递类一个 Runnable()对象。然后调用Thread对象的start()方法来为该线程执行必须的初始化操作。然后系统会自动调用Runnable的run()方法。

    示例代码:src/thread_runnable/ThreadRunnable.java

     1 public class ThreadRunnable{
     2     
     3     private static final String TAG = "LiftOff";
     4 
     5     public static void main(String[] args) {
     6         // TODO Auto-generated method stub        
     7         
     8         System.out.println("main start, " + Thread.currentThread().getName());
     9         for (int i=0; i<3; i++){
    10             Thread thread = new Thread(new CountDown());
    11             thread.start();
    12         }
    13         System.out.println("main end, " + Thread.currentThread().getName());
    14     }
    15 
    16 }

    输出结果: (每次执行的结果都有差别)

    可以看出,新启动了三个新线程,来输出各自的任务,并且从结果,还可以看出,三个线程的执行顺序都是随机的,并且每次执行的结果都不同。那么这就说明线程运行的时候是被混在一起的,这种线程的切换就是线程调度器来进行自动控制的。具有不确定性。而对于多核处理器,也有可能在几个不同的核上同时执行着几个线程,但是对于输出信息到控制台,(就是 System.out.println()语句),这种输出资源是只存在一份的。

    既然可以直接使用Thread()对象的start()方法来启动新线程,那为什么还要使用Runnable()对象来传递到Thread()对象的构造方法中,在Runnable对象的run()方法中来执行任务呢。原因如下:
    (1) java是单根继承,而Runnable是interface。方便了任务的继承。
    (2) 解耦,任务本身与线程分离,两者相互独立。也方便任务代码被多个线程共享。

    这几篇java多线程文章的demo代码下载地址 http://download.csdn.net/detail/yaowen369/9786452

    -------
    作者: www.yaoxiaowen.com
    github: https://github.com/yaowen369

  • 相关阅读:
    JavaScript常用设计模式
    js 判断l对象类型
    JavaScript编程(终极篇)
    微信小程序开发-滑动操作
    解决Jquery向页面append新元素之后事件的绑定问题
    C# list与数组互相转换
    C# “贝格尔”编排法
    C#数字格式化
    SQL从一个表查询数据插入/更新到另一个表
    全局唯一标识符 (GUID)
  • 原文地址:https://www.cnblogs.com/yaoxiaowen/p/6576779.html
Copyright © 2020-2023  润新知