P1: Java多线程全面详解

概述

进程,线程和多线程

进程: 是一个正在执行中的程序,每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元;
线程: 就是进程中的一个独立控制单元,线程在控制着进程的执行。一个进程中至少有一个线程。
多线程: 一个进程中不只有一个线程。

多线程优势

①、为了更好的利用cpu的资源,如果只有一个线程,则第二个任务必须等到第一个任务结束后才能进行,如果使用多线程则在主线程执行任务的同时 可以执行其他任务,而不需要等待;

②、进程之间不能共享数据,线程可以;

③、系统创建进程需要为该进程重新分配系统资源,创建线程代价比较小;

④、Java语言内置了多线程功能支持,简化了java多线程编程。

拓展

  • 并发与并行:
    . 并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。
    . 并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那 么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。
  • 线程安全:经常用来描绘一段代码。指在并发的情况之下,该代码经过多线程使用,线程的调度顺序不影响任何结果。这个时候使用多线程,我们只需要关注系统的内存,cpu是不是够用即可。
  • 同步:Java中的同步指的是通过人为的控制和调度,保证共享资源的多线程访问成为线程安全,来保证结果的准确. 在保证结果准确的同时,提高性能,才是优秀的程序。线程安全的优先级高于性能。

核心概念

  • 线程是独立的执行路径.
  • 在程序执行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程.
  • main()称之为主线程,为系统的入口,用于执行整个程序.
  • 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与系统紧密相关的,先后顺序是不能人为干预的.
  • 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制.
  • 线程会带来额外的开销,如CPU调度时间,并发数控制开销.
  • 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致.

继承Thread类

  • 继承Thread类,重写run()方法,调用start开启线程
  • 注意:线程开启不一定立即执行,由CPU调度执行
    [代码实例]
package com.TestThread;
//创建线程方式一:继承Thread类,重写run()方法,调用start开启线程
//注意:线程开启不一定立即执行,由CPU调度执行
public class ThreadDemo1 extends Thread {
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("我在写代码--"+i);
        }
    }
    public static void main(String[] args) {
        //main方法线程,主线程
        //创建一个线程对象
        ThreadDemo1 threadDemo1 = new ThreadDemo1();
        //调用start()方法开启线程
        threadDemo1.start();
        for (int i = 0; i < 1000; i++) {
            System.out.println("我在学习多线程--"+i);
        }
    }
}

多线程原理

  1. jvm中的多线程有很多,其中有负责定义代码运行的线程(这个从main方法开始执行的主线程),也有垃圾回收的线程(因为CPU的切换的不确定所以不定时执行。或者达到某个条件下执行)。

  2. 多线程的运行的根据CPU的切换完成的,也就是说怎么切换CPU说了算,所以多线程运行是随机的(CPU快速切换造成的)。

  3. 每次运行结果不一定相同,因为随机性造成的。

  4. 没一个线程都有运行的代码内容。这个称为线程的任务。创建一个线程就是为了去运行指定的任务代码。

网图下载

前提需要需要导commons-io-2.6.jar 测试代码如下:

import org.apache.commons.io.FileUtils;
 //练习Thread,实现多线程同步下载
import java.io.File;
import java.io.IOException;
import java.net.URL;
 
public class FileDownLoad extends Thread {
 
    String url; //网络图片地址
    String name; //保存的文件名
    public FileDownLoad (String url, String  name){
        this.url = url;
        this.name = name;
    }
    //下载图片的线程执行体
    @Override
    public void run() {
        FileLoad fileLoad = new FileLoad();
        fileLoad.dowload(url,name);
        System.out.println("图片下载成功了!!!");
    }
 
    public static void main(String[] args) {
        FileDownLoad t1 = new FileDownLoad("http://img.alicdn.com/tfscom/i1/821121421/O1CN012nazhz1MMrI77IGuX_!!821121421.jpg_250x250xz.jpg","4.jpg");
        FileDownLoad t2 = new FileDownLoad("http://gw.alicdn.com/bao/uploaded/TB1JJgEj8r0gK0jSZFnSuvRRXXa.jpg_440x440q75","5.jpg");
        FileDownLoad t3 = new FileDownLoad("//gw.alicdn.com/bao/uploaded/TB1.t7Aj1L2gK0jSZFmSuw7iXXa.jpg_440x440q75","6.jpg");
 
        t1.start();
        t2.start();
        t3.start();
    }
}
 
class FileLoad {
    //下载方法
    public void dowload(String url, String name){
        try{
        FileUtils.copyURLToFile(new URL(url),new File(name));
        }catch (IOException e){
            e.printStackTrace();
            System.out.println("IO异常!!!");
        }
    }
}

实现Runnable

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

推荐使用Runnable对象,因为Java单继承的局限性
[代码实例]

package com.TestThread;
//创建线程方式2:实现runnable接口,重写run方法,执行线程
public class ThreadDemo2 implements Runnable {
    @Override
    public void run() {
        //run方法体
        for (int i = 0; i < 20; i++) {
            System.out.println("我在写代码--"+i);
        }
    }

    public static void main(String[] args) {
        //创建runnable接口实现类对象
        ThreadDemo2 threadDemo2 = new ThreadDemo2();
        //创建线程对象,通过线程对象来开启我们的线程
        new Thread(threadDemo2).start();
        for (int i = 0; i < 1000; i++) {
            System.out.println("我在学习多线程--"+i);

        }
    }
}

小结

  • 继承Thread类
    1. 子类继承Thread类具备多线程能力
    2. 启动线程:子类对象.start()
    3. 不建议使用:避免OPP单继承局限性
  • 实现Runnable接口
    1. 实现接口Runnable具有多线程能力
    2. 启动线程:传入目标对象+Thread对象.start()
    3. 推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用

多线程详解

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值