zoukankan      html  css  js  c++  java
  • Java多线程中Thread与Runnable的区别

    Java多线程中Thread与Runnable的区别

    定义

    extends Thread
    • 子类继承Thread具备多线程能力,可以实现多线程;

    • 启动线程的方法:①创建子类对象 ②对象名.start();

    • 不建议使用:避免多线程OOP单继承的局限性(OOP:Object Oriented Programming,面向对象的编程、类似的还有OOD(面向对象的设计),OOA(面向对象的分析));

    implements Runnable
    • 实现Runnable接口具有多线程能力,可以实现多线程

    • 启动线程的方法:①创建子类对象 ②new Thread(对象).strart();

    • 推荐使用:避免OOP单继承的局限性,方便被同一个对象多次使用;

    实际上所有的多线程代码都是通过执行Thread的start()方法来运行的。所以不管是继承Thread类还是实现Runnable接口来实现多线程,最终都是通过Thread对象的API来控制线程的,因此熟悉Thread类的API是进行多线程编程的基础。(点击查看什么是API

    示例

    继承Thread实现多线程1
    package 多线程1;

    public class TestThread1 extends Thread {
       @Override
       public void run() {
           for (int i = 0; i < 20; i++) {
               System.out.println("子线程正在执行..."+i);
          }
      }

       public static void main(String[] args) {

           TestThread1 testThread1 = new TestThread1();
           testThread1.start();

           for (int i = 0; i < 500; i++) {
               System.out.println("主线程正在执行..."+i);
          }

      }
    }

    上述示例执行后可以看到:主线程和子线程的执行顺序本该是“先执行子线程、再执行主线程”,事实上却是主线程和子线程交替执行(无法人为控制,由CPU调度执行),这便是多线程的特征;

    继承Thread实现多线程2——下载网络图片
    package 多线程1;

    import org.apache.commons.io.FileUtils;

    import java.io.File;
    import java.io.IOException;
    import java.net.MalformedURLException;
    import java.net.URL;

    //练习网络下载图片
    public class TestThread2 extends Thread {

       private String url;
       private String name;

       public TestThread2(String url,String name){
           this.name=name;
           this.url=url;
      }


       @Override
       public void run() {
           WebDownloader webDownloader = new WebDownloader();
               webDownloader.Downloader(url,name);
           System.out.println("下载的文件名为 "+name);

      }

       public static void main(String[] args) {
           TestThread2 t1 = new TestThread2("https://img2020.cnblogs.com/blog/1230003/202006/1230003-20200615202249319-667650898.png","p1.jpg");
           TestThread2 t2 = new TestThread2("https://img2020.cnblogs.com/blog/1230003/202006/1230003-20200615202427336-668333955.png","p2.jpg");
           TestThread2 t3 = new TestThread2("https://img2020.cnblogs.com/blog/1230003/202006/1230003-20200615202435759-576754989.png","p3.jpg");

           t1.start();
           t2.start();
           t3.start();
      }
    }

    //下载器
    class WebDownloader{
       public void Downloader(String url,String name) {

           try {
               FileUtils.copyURLToFile(new URL(url),new File(name));
          } catch (IOException e) {
               e.printStackTrace();
               System.out.println("IO错误!");
          }
      }
    }

    注:代码中图片为网络上随机寻找

    由以上代码也可以看出:下载的三张图片的顺序本应该是"p1-->p2-->p3",事实上执行后发现三张图片的下载顺序是随机的(受CPU自由调度)。

    Runnable接口实现多线程1
    package 多线程1;

    public class TestThread4_Runnable implements Runnable {

       @Override
       public void run() {
           for (int i = 0; i < 10; i++) {
               System.out.println("我是小兔子"+i);
          }

      }

       public static void main(String[] args) {
           TestThread4_Runnable testThread4_runnable = new TestThread4_Runnable();
           Thread thread = new Thread(testThread4_runnable);
           thread.start();

           for (int i = 0; i < 800; i++) {
               System.out.println("但我是一只小脑斧哦~"+i);
          }
      }
    }

    上述代码的执行结果也是随机的,无法根据代码的编写顺序来判断执行顺序。

    Runnable接口实现多线程2——龟兔赛跑
    package 多线程1;

    public class Race implements Runnable {

       private String winner=null;

       @Override
       public void run() {
           for (int i = 0; i <= 100; i++) {

               if(Thread.currentThread().getName().equals("兔子") && i%5==0) {   //模拟兔子休息(1ms)
                   try {
                       Thread.sleep(1);
                  } catch (InterruptedException e) {
                       e.printStackTrace();
                  }
              }
               boolean winner = Win(i);
               if(winner)
                   break;
               System.out.println(Thread.currentThread().getName() + "跑了" + i + "步");
      }
      }

       public boolean Win(int steps){  //判断比赛是否结束
           if(winner!=null)
               return true;
           else  if(steps==100) {
               winner = Thread.currentThread().getName();
               System.out.println(winner + "已经完成比赛!");
               return true;
          }
           else
               return false;
      }

       public static void main(String[] args) {
           Race race = new Race();

           new Thread(race,"兔子").start();
           new Thread(race,"乌龟").start();
      }
    }

    上述代码模拟了龟兔赛跑,乌龟和兔子“随机跑步”,兔子在中途“频繁”休息,执行结果最终是乌龟成为了winner!

    Thread.sleep()方法调用的目的是不让当前线程独自霸占CPU,以留出一定时间给其他线程执行的机会。 实际上所有的多线程代码执行顺序都是不确定的,每次执行的结果都是随机的。

    但由于CPU的执行速度非常快,在测试的数量比较少的情况下可能无法看出随机执行的现象!

  • 相关阅读:
    loushang框架的开发中关于BSP的使用,将写好的功能模块部署到主页界面结构上
    浪潮“楼上”开发平台简介
    New博客园新的开始!
    python相关
    day20 函数闭包与装饰器
    计算机基础
    day19 生成器函数
    简历
    day18 迭代器
    数据库基础(代码)
  • 原文地址:https://www.cnblogs.com/awong18/p/13143946.html
Copyright © 2011-2022 走看看