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();
        }
    }
}
原文地址:https://www.cnblogs.com/obge/p/13636383.html