Java多线程之线程的3种实现方式

1、进程和线程

  • 进程:process

  • 线程:thread

  • 进程是执行程序的一次执行过程,动态的概念,是系统资源分配的单位

  • 进程中可以包含多个线程,线程是CPU调度和执行的单位。

  • 一个进程至少包含一个线程。

  • 很多的多线程是模拟出来的。真正的多线程是指 多核,也就是多个CPU。

  • 即使在一个CPU的情况下,在同一时间CPU只能执行一条代码,只是切换的时间很快,所以会有同时执行的错觉

  • 对于同一份资源(临界资源),会存在抢夺的情况,需要加入并发控制

  • 每个线程在自己的工作内存交互,内存控制不当会造成数据的不一致。

2、创建方式

  • 继承Thread类
  • 实现Runnable接口
  • 实现Callable接口

3、Thread类

  • 自定义线程类,继承Thread类
  • 重写run()方法,编写执行代码
  • 创建线程对象,调用start()方法启动线程

在这里插入图片描述

public class MyThreadOne extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("run方法执行");
        }
    }

    public static void main(String[] args) {

        MyThreadOne myThreadOne = new MyThreadOne();
        //run方法执行完之后,才会执行main方法
        myThreadOne.run();
        //start()和main()是交替执行的
        myThreadOne.start();
        for (int i = 0; i < 3000; i++) {
            System.out.println("main方法执行");
        }
    }
}

部分输出结果

273次main方法执行
第10次run方法执行
第274次main方法执行
第11次run方法执行
第275次main方法执行
第12次run方法执行
第276次main方法执行
第13次run方法执行
第277次main方法执行
第14次run方法执行
第278次main方法执行
第15次run方法执行
第279次main方法执行
第16次run方法执行
第280次main方法执行

例2 下载图片

//下载类
public class MyThreadTwo extends Thread {
    private String url;
    private String name;
    public MyThreadTwo(String url,String name){
        this.name = name;
        this.url = url;
    }
	//重写run方法
    @Override
    public void run() {
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url,name);
        System.out.println("下载图片"+name+"完毕");
    }
	//主方法
    public static void main(String[] args) {
        MyThreadTwo myThreadTwo1 = new MyThreadTwo("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1605431864179&di=dfe29259d39d50b30bd78a2fd520e5df&imgtype=0&src=http%3A%2F%2Fa0.att.hudong.com%2F30%2F29%2F01300000201438121627296084016.jpg","1.jpg");
        MyThreadTwo myThreadTwo2 = new MyThreadTwo("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1605432047363&di=72a55f655352297dbef4e2cedd851c49&imgtype=0&src=http%3A%2F%2Fa3.att.hudong.com%2F55%2F22%2F20300000929429130630222900050.jpg","2.jpg");
        MyThreadTwo myThreadTwo3 = new MyThreadTwo("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1605432093023&di=d929c258e7d8ac88be9b900ef2e38a30&imgtype=0&src=http%3A%2F%2Fa2.att.hudong.com%2F06%2F02%2F19300534106437134465026151672.jpg","3.jpg");
        myThreadTwo1.start();
        myThreadTwo2.start();
        myThreadTwo3.start();
    }

}
//下载器
class WebDownloader{
  public void downloader(String url,String name){
      try {
          FileUtils.copyURLToFile(new URL(url),new File(name));
      } catch (IOException e) {
          e.printStackTrace();
      }
  }

}

下载图片1.jpg完毕
下载图片3.jpg完毕
下载图片2.jpg完毕

4、Runnable

  • 实现Runnable接口
  • 重写run方法
  • 执行线程需要丢入runnable接口的实现类
  • 调用start()
public class MyThreadThree implements  Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("run方法执行");
        }
    }

    public static void main(String[] args) {
        
        //启动方式不一样
        MyThreadThree myThreadThree = new MyThreadThree();
        //丢入 runnable的实现类
        new Thread(myThreadThree).start();

        for (int i = 0; i < 3000; i++) {
            System.out.println("main方法执行");
        }
    }
}

5、推荐使用

  • 继承Thread 类 不建议使用。避免OOP单继承局限性
  • 实现Runnable接口 推荐使用。灵活方便,一个对象可以被多个线程使用。

6、Callable

  • 实现Callable接口,需要返回值类型
  • 重写call方法,需要抛出异常
  • 创建目标对象
  • 创建执行服务:
    • ExecutorService ser = Executor.newFixedThreadPool(1);
  • 提交执行
    • Futureresult1 = ser.submit(1);
  • 获取结果
    • boolean r1 = result1.get();
  • 关闭服务
    • ser.shutdownNow();

例子

import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;

public class MyThreadSix implements Callable<Boolean> {

    private String url;
    private String name;
    public MyThreadSix(String url,String name){
        this.name = name;
        this.url = url;
    }
    //重写call方法
    @Override
    public Boolean call() {
        WebDownload webDownload = new WebDownload();
        webDownload.downloader(url,name);
        System.out.println("下载图片"+name+"完毕");
        return true;
    }
    //主方法
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyThreadSix t1 = new MyThreadSix("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1605431864179&di=dfe29259d39d50b30bd78a2fd520e5df&imgtype=0&src=http%3A%2F%2Fa0.att.hudong.com%2F30%2F29%2F01300000201438121627296084016.jpg","1.jpg");
        MyThreadSix t2 = new MyThreadSix("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1605432047363&di=72a55f655352297dbef4e2cedd851c49&imgtype=0&src=http%3A%2F%2Fa3.att.hudong.com%2F55%2F22%2F20300000929429130630222900050.jpg","2.jpg");
        MyThreadSix t3 = new MyThreadSix("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1605432093023&di=d929c258e7d8ac88be9b900ef2e38a30&imgtype=0&src=http%3A%2F%2Fa2.att.hudong.com%2F06%2F02%2F19300534106437134465026151672.jpg","3.jpg");
        // 创建执行服务:
        ExecutorService ser = Executors.newFixedThreadPool(3);
        // 提交执行
        Future<Boolean> r1= ser.submit(t1);
        Future<Boolean> r2= ser.submit(t2);
        Future<Boolean> r3= ser.submit(t3);
        // 获取结果
        boolean rs1 = r1.get();
        boolean rs2 = r2.get();
        boolean rs3 = r3.get();

        System.out.println(rs1);
        System.out.println(rs2);
        System.out.println(rs3);
        // 关闭服务
        ser.shutdownNow();
    }

}
//下载器
class WebDownload{
    public void downloader(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

下载图片3.jpg完毕
下载图片1.jpg完毕
下载图片2.jpg完毕
true
true
true

  • 好处
    • 定义返回值
    • 可以抛出异常
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值