1、概念与线程的创建

概念

程序:指令和数据的有序集合,本身没有运行的含义,是一个静态的概念

进程:程序的一次执行过程,是一个动态的概念,有自己的生命周期,是系统资源分配的基本单位

线程:是CPU调度和执行的基本单位

  • 一个程序运行时至少有一个进程,一个进程至少有一个线程
  • 程序运行时,即使自己没有创建线程,在java中也会有两个线程,即主线程和守护线程
  • main()称为主线程,是系统执行的入口
  • 当有多个线程时,线程的运行由调度器安排调度。调度器与操作系统密切相关,先后顺序不能人为干预。线程具有优先级,但是最终调用谁,还得看CPU
  • 系统会为进程分配资源,进程中的多个线程会共享这个资源。因此多线程会存在抢夺资源的问题,需要加入并发控制
  • 线程会带来额外开销,如CPU调度、并发控制开销
  • 很多多线程都是模拟出来的,即在一个CPU的情况下,同一个时间点,CPU只能执行一个线程,但是切换速度很快,所以会以为是多个线程同时执行。真正的多线程是指有多个CPU。即多核。

普通方法调用和多线程

在这里插入图片描述

三种创建线程的方式

Thread类

Thread实现了Runnable接口
步骤:1、自定义线程类继承Thread类;2、重写run()方法,编写线程执行代码;3、创建自定义线程对象,调用start()方法启动线程

//创建线程方式一:继承Thread类,重写run方法,调用start开启线程
public class TestThread01 extends Thread{
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 2000; i++) {
            System.out.println("我在看代码---"+i);
        }
    }
    public static void main(String[] args) {
        //main主线程
        //创建一个线程对象
        TestThread01 testThread01 = new TestThread01();
        //线程启动
        testThread01.start();

        for (int i = 0; i < 2000; i++) {
            System.out.println("我在学习---"+i);
        }
    }
}

Runnable接口

推荐使用这个方法,1、因为java单继承的局限性,最好是实现接口而不是继承;2、静态代理思想,可以一份资源,多个代理(后面章节详细讲)
步骤:1、自定义类实现Runnable接口;2、实现run()方法,编写线程执行体;3、创建自定义类的对象,并将其作为Thread对象的参数 ;4、start()

下面的例子自己开辟了三个线程,只需要一个自定义类对象,三个Thread对象。还可以给线程起名字new Thread(test,"A")以及获得当前正在执行的线程名字Thread.currentThread().getName()

public class TestThread01 implements Runnable{
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName() + ": "+ "我在看代码---"+i);
        }
    }

    public static void main(String[] args) {
        //main主线程
        //启动三个线程,每个线程各自都去执行run方法,都输出2000句
        TestThread01 test = new TestThread01();
        new Thread(test,"A").start();
        new Thread(test,"B").start();
        new Thread(test,"C").start();

        for (int i = 0; i < 20; i++) {
            System.out.println("我在学习---"+i);
        }
    }
}

Callable接口(目前了解)

实现Callable接口,重写call方法,有返回值,需要指定返回值类型(下面代码中指定为Boolean类型)
步骤:1、创建目标对象;2、创建服务ExecutorService service = Executors.newFixedThreadPool(n);3、提交执行Future<Boolean> submit1 = service.submit(t1);4、获取结果submit1.get();5、关闭服务service.shutdownNow()

举例:开启三个线程测试

public class TestCallable01 implements Callable<Boolean>{
    @Override
    public Boolean call() {
        //run方法线程体
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName() + "我在看代码---"+i);
        }
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        TestCallable01 t1 = new TestCallable01();
        TestCallable01 t2 = new TestCallable01();
        TestCallable01 t3 = new TestCallable01();
        //创建服务,指定线程池中的线程数
        ExecutorService service = Executors.newFixedThreadPool(3);
        //提交线程
        Future<Boolean> submit1 = service.submit(t1);
        Future<Boolean> submit2 = service.submit(t2);
        Future<Boolean> submit3 = service.submit(t3);
        //获取结果
        submit1.get();
        submit2.get();
        submit3.get();
        //关闭服务
        service.shutdownNow();
    }
}

测试:多线程下载图片

需要先导入一个commons-io-2.6.jar包,用FileUtils.copyURLToFile(new URL(url), new File(name))方法从网络上下载资源,传入URL和存储地址

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
//继承Thread
public class TestThread02 extends Thread{
    private String url;
    private String name;

    @Override
    public void run() {
        try {
            new WebDowner().down(url,name);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(name+"下载异常");
        }
    }

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

    public static void main(String[] args) {
        TestThread02 t1 = new TestThread02("https://img0.baidu.com/it/u=2151136234,3513236673&fm=26&fmt=auto&gp=0.jpg", "C:\\Users\\Bi\\Desktop\\1.jpg");
        TestThread02 t2 = new TestThread02("https://c-ssl.duitang.com/uploads/item/201503/21/20150321160159_vVxSC.thumb.1000_0.jpeg","2.jpg");
        TestThread02 t3 = new TestThread02("https://c-ssl.duitang.com/uploads/item/201503/12/20150312231447_THNsw.thumb.1000_0.jpeg","3.jpg");

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

class WebDowner{
    //下载方法
    public void down(String url, String name) throws Exception {
        FileUtils.copyURLToFile(new URL(url), new File(name));
        System.out.println(name+"下载完毕");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
进程和线程是操作系统中的两个基本概念,它们都是用来执行程序的执行单元,但在一些方面有着明显的区别。 1. 进程(Process): - 进程是程序在执行过程中的一个实例。 - 每个进程都有自己的独立内存空间,包括代码段、数据段和堆栈段。 - 进程之间相互独立,拥有各自的资源,通信需要通过进程间通信(IPC)机制。 - 进程拥有自己的进程控制块(PCB),用于描述进程的状态、资源和调度信息。 2. 线程(Thread): - 线程是进程中的一个执行单元。 - 多个线程可以共享同一个进程的内存空间,包括代码段、数据段和堆栈段。 - 线程之间共享进程的资源,如打开的文件、信号处理等。 - 线程由线程控制块(TCB)来描述,每个线程有自己的栈和寄存器上下文。 区别: 1. 资源占用:每个进程都有独立的内存空间和系统资源,而线程共享进程的资源。 2. 创建销毁开销:创建或销毁进程比线程开销大,因为进程需要分配独立的内存空间和系统资源,而线程只需要创建线程控制块。 3. 切换开销:进程切换的开销较大,需要保存和恢复整个进程的上下文,而线程切换只需要保存和恢复线程的上下文。 4. 通信和同步:进程间通信需要使用进程间通信机制,如管道、消息队列等。线程间通信和同步相对容易,可以使用共享内存、信号量、互斥量等机制。 总结: 进程和线程都是用于执行程序的执行单元,但进程是资源分配的基本单位,线程是CPU调度的基本单位。多线程比多进程更轻量级,线程之间的切换开销更小,但进程之间相互独立,安全性更高。在实际应用中,需要根据具体需求选择使用进程还是线程。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值