zoukankan      html  css  js  c++  java
  • Java ----- 线程(Thread)(二)创建线程

    Java程序中的 public static void main()  方法时主线程的入口,当运行Java程序时,会先执行这个方法。

    程序运行的时候系统(cpu)会分配一个进程用于执行该程序,在Java中,即使在运行的程序中没有创建线程,后台也会有多个线程运行,如主线程、gc 线程,其中主线程为main函数是程序入口,用于执行整个程序,gc 为jvm 的垃圾回收机制,他们是相互独立的执行路径,当开辟了多个线程时,线程的运行由调度器进行安排调度,线程的先后顺序是不能人为干预的,因为调度器是操作系统的cpu进行调度,因此线程会增加额外的开销,可以通过并发进行控制开销。并发还有个好处是,可以避免在对同一份资源进行操作时,存在的资源抢夺问题,在每个线程在自己的工作内交互时,内存控制不当会造成数据不一致。

    注意:

    (1)、每个程序至少自动拥有一个线程,称为主线程。

    (2)、当程序加载到内存时启动主线程。

    (3)、开发中用户编写的线程一般是指除了主线程之外的其他线程,主线程调用start()方法,子线程执行run 方法,多条执行路径,主线程与子线程交替执行。

    使用一个线程的主要步骤:

    (1)、定义一个线程,同时指明这个线程索要执行的代码,即期望完成的功能

    (2)、创建线程对象

    (3)、启动线程

    (4)、终止线程

    Thread 类常用的方法:

    java 提供了java.lang.Thread 类支持多线程编程,该类提供了大量的方法来控制和操作线程,如下

    定义一个线程类常见的两种方法:继承java.lang.Thread 类和实现java.lang.Runnable 接口

    1、使用Thread 类创建线程

    创建线程时继承Thread 类并重写Thread类的run 方法。Thread 类的run 方法是线程要执行操作任务的方法,所以线程要执行的操作代码都需要写在run() 方法中,并通过调用start() 方法来启动线程。

    使用继承Thread 类的方式创建线程主要步骤 

    (1)、定义一个类继承Thread 类,重写run 方法,

    (2)、重写run 方法,并在方法中写需要输出的数据

    (3)、创建线程对象

    (4)、调用start() 方法启动线程

     注意:创建对象时不会执行线程,必须调用线程对象的start() 方法才会使线程开始运行。

    package com.obge.threadstu;
    
    public class ThreadStu extends Thread {
    
        private int icount =0;
        //重写run 方法
        public void run(){
    //        while(icount <5){
    //            icount ++;
    //            System.out.println("while的值:"+icount);
    //        }
    
            do{
                icount ++;
                System.out.println("do_while的值:"+icount);
            }while (icount<4);
    
    //        for(;icount<3;icount++){
    //            System.out.println("for的值:"+icount);
    //        }
    
    
        }
    
    }
    
    
    
    package com.obge.threadstu;
    
    public class TestThread {
        public static void main(String[] args) {
            //实例化线程对象
            ThreadStu threadStu = new ThreadStu();
            threadStu.start();
        }
    
    
    }

    缺点:虽然,使用继承Thread的方式简单明了,但是如果定义的类已经继承了其他类则无法在继承Thread 类。所以引入了另一种方式实现Runnable 接口创建线程

    在来一个小例子:借助线程从网络中下载文件

    2、使用Runnable 接口创建线程

    Runnable 接口中声明了一个run()方法(即public void run() )

    一个类可以通过实现Runnable 接口并实现其 run() 方法完成线程的所有活动,其中以实现的run() 方法称为该对象的线程体。任何实现Runnable 接口的对象都可以作为一个线程的目标对象。

    使用实现Runnable 接口方式创建对象的主要步骤:

    (1)、定义一个类实现java.lang.Runnable 接口

    (2)、实现该接口的run()方法,并在方法中写需要输出的数据

    (3)、创建线程对象

    (4)、调用start() 方法启动线程

    使借助Thread thread = new Thread( new RunnableStu());创建对象

    package com.obge.threadstu;
    
    public class RunnableStu implements Runnable{
        //重写注解  一个内建注解
        @Override
        public void run() {
            for(int i = 0;i<3;i++){
                System.out.println("for的值:"+i);
            }
    
        }
    }
    
    package com.obge.threadstu;
    
    public class TestThread {
        public static void main(String[] args) {
            //实例化线程对象
            //ThreadStu threadStu = new ThreadStu();
            Thread thread = new Thread( new RunnableStu());
            thread.start();
        }
    
    
    }

     另一个小例子

    两种方式比较:

    直接继承Thread 类的方式编写简单,可以直接操作线程,适合单重继承的情况

    实现Runnable接口方式,当一个线程继承另一个类时,只能实现Runnable 接口的方法创建线程,使多个线程之间使用同一个Runnable对象(因为java 只能单继承,可以实现多个接口)

    3、实现Callable 接口

    主要步骤:

    (1)、实现Callable 接口,需要返回值类型

    (2)、重写call 方法 ,需要抛出异常

    (3)、创建目标对象

    (4)、创建执行服务 :ExecutorService executorService = Executors.newFixedThreadPool();

    (5)、提交执行:Future<Boolean> result1 = executorService.submit(thread1);

    (6)、获取结果:boolean r1 = result1.get();

    (7)、关闭服务:executorService.shutdown();

    package com.obge.threadstu;
    
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    /*
     * Callable 可以抛出异常也可以定义返回值
     */
    public class CallableStu implements Callable<Boolean>{
        //声明创建变量
        private String url;
        private String name;
        //提供构造方法,用于对象创建,对类进行初始化
        public CallableStu(String url,String name) {
            this.url = url;
            this.name = name;
        }
        //通过实现Callable 方式,创建线程
        @Override
        public Boolean call() throws Exception {
            WebDownloader webDownloader = new WebDownloader();
            webDownloader.downloads(url, name);
            System.out.println("下载图片的名字:"+name);
            return true;
        }    
        //程序入口
        public static void main(String[] args) throws InterruptedException, ExecutionException {        
            //实例化线程
            CallableStu thread1 = new CallableStu("https://img.alicdn.com/imgextra/i4/121853076/O1CN01kOYLk81Yaqvw2jDOc_!!0-saturn_solar.jpg_468x468q75.jpg_.webp","img1.jpg");
            CallableStu thread2 = new CallableStu("https://mirrors.bfsu.edu.cn/apache//commons/io/binaries/commons-io-2.8.0-bin.zip","file1.jpg");
            CallableStu thread3 = new CallableStu("https://img.alicdn.com/imgextra/i4/15012183/O1CN01yDHHYJ1RzrGb2Up4z_!!0-saturn_solar.jpg_468x468q75.jpg_.webp","img2.jpg");
            CallableStu thread4 = new CallableStu("https://img.alicdn.com/imgextra/i3/127372649/O1CN01dadNEf1VRHpmz7f66_!!0-saturn_solar.jpg_468x468q75.jpg_.webp","img3.jpg");
            //线程执行,其顺序由不能控制
            
            //创建执行服务,将四个线程放到池子里
            ExecutorService executorService = Executors.newFixedThreadPool(4);
            //提交执行
            Future<Boolean> result1 = executorService.submit(thread1);
            Future<Boolean> result2 = executorService.submit(thread2);
            Future<Boolean> result3 = executorService.submit(thread3);
            Future<Boolean> result4 = executorService.submit(thread4);
            //获取结果    
            boolean r1 = result1.get();
            boolean r2 = result2.get();
            boolean r3 = result3.get();
            boolean r4 = result4.get();
            System.out.println("打印结果为:r1="+r1+",r2="+r2+",r3="+r3+",r4="+r4);
            //关闭服务
            executorService.shutdown();
        }
    
    }

    下载类

    package com.obge.threadstu;
    
    import java.io.File;
    import java.io.IOException;
    import java.net.MalformedURLException;
    import java.net.URL;
    
    import org.apache.commons.io.FileUtils;
    //下载类
    public class WebDownloader {
        //下载方法
        public void downloads(String url,String name) {        
            try {
                FileUtils.copyURLToFile(new URL(url),new File(name));
            } catch (MalformedURLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
  • 相关阅读:
    Solution: Win 10 和 Ubuntu 16.04 LTS双系统, Win 10 不能从grub启动
    在Ubuntu上如何往fcitx里添加输入法
    LaTeX 笔记---Q&A
    Hong Kong Regional Online Preliminary 2016 C. Classrooms
    Codeforces 711E ZS and The Birthday Paradox
    poj 2342 anniversary party
    poj 1088 滑雪
    poj 2479 maximum sum
    poj 2481 cows
    poj 2352 stars
  • 原文地址:https://www.cnblogs.com/obge/p/13636383.html
Copyright © 2011-2022 走看看