线程与进程

(1)线程是“进程代码段”的一次顺序执行流程。一个进程由一个或多个线程组成,一个进程至少有一个线程。

(2)线程是CPU调度的最小单位,进程是操作系统分配资源的最小单位。线程的划分尺度小于进程,使得多线程程序的并发性高。

(3)线程是出于高并发的调度诉求从进程内部演进而来的。线程的出现既充分发挥了CPU的计算性能,又弥补了进程调度过于笨重的问题。

(4)进程之间是相互独立的,但进程内部的各个线程之间并不完全独立。各个线程之间共享进程的方法区内存、堆内存、系统资源

(5)切换速度不同:线程上下文切换比进程上下文切换要快得多。所以,有的时候,线程也称为轻量级进程。

创建多线程

Java中创建多线程有三种方法:

  • Thread类
  • Runnable接口
  • Callable接口

先封装一个输出语句,因为输出语句实在是太长了

class PRT{
    public static void prtln(Object obj){
            System.out.println(obj);
    }
    public static void prt(Object obj){
        System.out.print(obj);
    }
}

1. 使用Thread类

步骤:

  1. 自定义线程继承Thread
  2. 重写run()方法
  3. 创建线程对象,调用start()方法启动线程
class TestThread1 extends Thread{

     @Override
     public void run() {
         
         // 线程内
         for (int i = 0; i < 1000; i++) {
             PRT.prtln("run "+i);
         }
     }
 }

public class Main {

    public static void main(String[] args) {

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

//        主线程
        for (int i = 0; i < 1000; i++) {
            PRT.prtln("main "+i);
        }
    }
}

运行一下,可见内容是穿插输出的

image-20211227172322108
image-20211227172322108

多线程下载图片 Thread

首先导入apache commons-io包(自行下载即可,或者用maven)

package cn.vwmwv.thread;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;
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);
        PRT.prtln("下载完成,文件名为:"+name);
    }

    public static void main(String[] args) {
        TestThread2 t1 = new TestThread2("https://s4.ax1x.com/2021/12/27/TDBt74.jpg","1.jpg");
        TestThread2 t2 = new TestThread2("https://s4.ax1x.com/2021/12/27/TDBt74.jpg","2.jpg");
        TestThread2 t3 = new TestThread2("https://s4.ax1x.com/2021/12/27/TDBt74.jpg","3.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();
            PRT.prtln("IO异常,downloader方法异常");
        }
    }
}

下载完成,显示如下

image-20211227174811280
image-20211227174811280

2. 实现Runnable接口

步骤:

  1. 定义MyRunnable类实现Runnable接口
  2. 实现run()方法,编写线程执行体
  3. 创建线程对象,调用start()方法启动线程
package cn.vwmwv.thread;

// Runnable
public class TestThread3 implements Runnable {

    @Override
    public void run() {
        // 线程内
        for (int i = 0; i < 1000; i++) {
            PRT.prtln("run "+i);
        }
    }

    public static void main(String[] args) {
        TestThread3 testThread3 = new TestThread3();
        new Thread(testThread3).start();

        // 主线程
        for (int i = 0; i < 1000; i++) {
            PRT.prtln("main "+i);
        }
    }
}

可见,依旧是穿插输出的:

image-20211227181717443
image-20211227181717443

多线程下载图片 Runnable

// 多线程下载图片 Runnable
public class DownPic implements Runnable {
    private String url;
    private String name;
    public DownPic(String url,String name){
        this.name = name;
        this.url = url;
    }
    @Override
    public void run() {
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url,name);
        PRT.prtln("下载完成,文件名为:"+name);
    }

    public static void main(String[] args) {
        DownPic t1 = new DownPic("https://s4.ax1x.com/2021/12/27/TDBt74.jpg","1.jpg");
        DownPic t2 = new DownPic("https://s4.ax1x.com/2021/12/27/TDBt74.jpg","2.jpg");
        DownPic t3 = new DownPic("https://s4.ax1x.com/2021/12/27/TDBt74.jpg","3.jpg");
        new Thread(t1).start();
        new Thread(t2).start();
        new Thread(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();
            PRT.prtln("IO异常,downloader方法异常");
        }
    }
}

3. 实现Callable接口

步骤:

  1. 实现Callble接口,需要返回值类型
  2. 重写call方法,需返回异常
  3. 创建目标对象
  4. 创建执行服务
  5. 提交执行
  6. 获取结果
  7. 关闭服务

多线程下载图片 Callable

package cn.vwmwv.thread;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;

public class TestCallable implements Callable<Boolean> {
    private String url;
    private String name;
    public TestCallable(String url,String name) {
        this.name = name;
        this.url = url;
    }

    @Override
    public Boolean call() throws Exception {
        CallWebDownloader webDownloader = new CallWebDownloader();
        webDownloader.downloader(url,name);
        PRT.prtln("下载完成,文件名为:"+name);
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        String url = "https://cdn-ali-img-shstaticbz.shanhutech.cn/bizhi/staticwp/202106/87ad8b2009c489546b5d0a9482b5f08a--164538143.jpg";
//        String name = "1.jpg";
        TestCallable t1 = new TestCallable(url,"1.jpg");
        TestCallable t2 = new TestCallable(url,"2.jpg");
        TestCallable t3 = new TestCallable(url,"3.jpg");

        // 创建执行服务
        ExecutorService service = Executors.newFixedThreadPool(3);
        // 提交 执行
        Future<Boolean> r1 = service.submit(t1);
        Future<Boolean> r2 = service.submit(t2);
        Future<Boolean> r3 = service.submit(t3);
        // 获取结果
        Boolean rs1 = r1.get();
        Boolean rs2 = r2.get();
        Boolean rs3 = r3.get();
        // 打印结果
        PRT.prtln(rs1);
        PRT.prtln(rs2);
        PRT.prtln(rs3);

        // 关闭服务
        service.shutdown();

    }
}
class CallWebDownloader{
    public void downloader(String url,String name)  {
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));

        }catch (IOException e){
            e.printStackTrace();
            PRT.prtln("IO异常,downloader方法异常");
        }
    }
}

image-20211228143858501
image-20211228143858501

参考资料