《JAVA300集》多线程_入门-day19

目录

多线程

一、前言

二、进程和线程

三、多线程创建的方法

(1)继承Thread类实现多线程的步骤

(2)通过多线程下载网络图片

(3)实现Runnable接口完成多线程 (最常用)

(4)共享资源(模拟抢票)

(5)实现Callable接口完成多线程(了解)


 

多线程

一、前言

多线程是Java语言的重要特性,大量应用于网络编程、服务器端程序的开发等。我们可以上万人同时访问某个网站,也是基于网站服务器的多线程原理。

二、进程和线程

进程:程序是一个静态的概念,一般对应于操作系统中的一个可执行文件,比如:我们要启动war 3打游戏,则双击war 3的可执行程序,将war3的程序加载到内存中,开始执行程序,这就产生了进程。 执行中的程序叫做进程(Process),是一个动态的概念

进程的特点

(1)进程是程序的一次动态执行过程, 占用特定的地址空间。

(2)每个进程由3部分组成:cpu、data、code。每个进程都是独立的,保有自己的cpu时间,代码和数据,即便用同一份程序产生好几个进程,它们之间还是拥有自己的这3样东西,这样的缺点是:浪费内存,cpu的负担较重。

(3)多任务(Multitasking)操作系统将CPU时间动态地划分给每个进程,操作系统同时执行多个进程,每个进程独立运行。以进程的观点来看,它会以为自己独占CPU的使用权。

(4)进程间的切换会有较大的开销。

线程(thread)是指一个进程中开辟多条路径可以理解为独立的执行路径,充分利用CPU。

线程的特点

(1)每个进程至少开辟1个线程,可以产生多个线程。同一进程的多个线程也可以共享此进程的某些资源(比如:代码、数据)。

(2)main()称为主线程,为系统的入口点,用于执行整个程序。

(3)在一个进程中,如果开辟了多个线程,线程的运行则由调度器安排调度,先后顺序是由操作系统决定的,不能人为干预。

(4)对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制。

(5)线程会带来额外的开销,如cpu调度时间,并发控制开销。

(6)加载和存储主内存不当会造成数据不一致。

(7)线程的启动、中断、消亡,消耗的资源非常少。

总结:

(1)进程可以理解为资源分配的单位,线程是调度和执行的单位

(2)真正的多线程是指有很多CPU,很多时候多线程是模拟出来的。

(3)系统在运行的时候会为每个进程分配不同的内存区域,但是不会为线程分配内存,线程只能共享它所属进程的资源。

特殊的一种线程:守护线程

(1)守护线程是为其他线程服务的线程;

(2)所有非守护线程都执行完毕后,虚拟机退出;

(3)守护线程不能持有需要关闭的资源(如打开文件等)

三、多线程创建的方法

三种创建多线程的方法

(1)继承Thread类

(2)实现Runnable接口 (最常用)

(3)实现Callable接口

(1)继承Thread类实现多线程的步骤

 1. 在Java中负责实现线程功能的类是java.lang.Thread 类。

 2. 可以通过创建Thread的实例来创建新的线程。

 3. 每个线程都是通过某个特定的Thread对象所对应的方法run( )来完成其操作的,方法run( )称为线程体。

4. 通过调用Thread类的start()方法来启动一个线程

package Thread;
/*
* 创建线程方式一
* 1、创建:继承Thread+重写run
* 2、启动:创建子类对象+start
* */
public class StartThread extends Thread {
    //线程的入口点
    @Override
    public void run() {
        for(int i=0;i<5;i++){
            System.out.println("一边听歌");
        }
    }

    public static void main(String[] args) {
        //启动线程
        StartThread st = new StartThread();
        st.start(); //开启一个新线程
        for(int i=0;i<5;i++){
            System.out.println("一边coding");
        }
    }
}

运行结果: 或  等        因为线程运行的先后顺序由操作系统决定。

(2)通过多线程下载网络图片

下载工具代码

import org.apache.commons.io.FileUtils;

import java.io.IOException;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;

/*
* 下载图片
* */
public class WebDownloader {
        //下载工具
        public void download(String url, String name){
            try{
                FileUtils.copyURLToFile(new URL(url),new File(name));
            }catch (MalformedURLException e){
                e.printStackTrace();
                System.out.println("不合法的url");
            }catch (IOException e){
                e.printStackTrace();
                System.out.println("图片下载失败了");
            }
        }
}

调用下载工具,实现多线程下载图片

public class TDownloader extends Thread {
    private String url; //运程路径
    private String name; //存储名字

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

    @Override
    public void run() {
        WebDownloader wd = new WebDownloader();
        wd.download(url,name);
        System.out.println(name);
    }

    public static void main(String[] args) {
        TDownloader td1 = new TDownloader("https://tse3-mm.cn.bing.net/th/id/OIP.Tlumx9iXVC4rqPbISLZaRQHaF7?w=200&h=160&c=7&o=5&pid=1.7","1.jpg");
        TDownloader td2 = new TDownloader("https://tse1-mm.cn.bing.net/th/id/OIP.qwg11Rs1diETRMdP0WS6zQHaE-?w=200&h=134&c=7&o=5&pid=1.7","2.jpg");
        TDownloader td3 = new TDownloader("https://tse2-mm.cn.bing.net/th/id/OIP.zLNUiUPPCzf21pgCBJdXwAHaJy?w=200&h=265&c=7&o=5&pid=1.7","3.jpg");

        //启动三个线程,这三个的执行完成顺序是不固定的
        td1.start();
        td2.start();
        td3.start();
    }
}

(3)实现Runnable接口完成多线程 (最常用)

/*
* 创建线程方式二
* 1、创建:实现Runnable接口+重写run
* 2、启动:创建实现类对象+Thread对象+start
* */
public class StartRun implements Runnable{
    @Override
    public void run() {
        for(int i=0;i<20;i++){
            System.out.println("一边听歌");
        }
    }

    public static void main(String[] args) {
        //创建实现类对象
        StartRun sr = new StartRun();
        //创建代理类对象
        Thread t = new Thread(sr);
        //启动
        t.start();
        // 等于匿名使用  new Thread(new StartRun()).start();
        for(int i=0;i<5;i++){
            System.out.println("一边coding");
        }
    }
}

 这个方法的好处就是避免单继承的局限性,优先使用接口,而且这个方法会方便共享资源

启动线程简写版:new Thread(new StartRun()).start

(4)共享资源(模拟抢票)

/*
* 共享资源(这里需要保证线程安全)
* */
public class Web12306 implements Runnable{
    //票数
    private int ticketNums = 10;
    @Override
    public void run() {
        while(true){
            if(ticketNums==0){
                break;
            }
            System.out.println(Thread.currentThread().getName()+"抢到了"+ticketNums--+"号票");
        }
    }

    public static void main(String[] args) {
        //1份资源
        Web12306 web = new Web12306();
        //多个代理
        new Thread(web,"抢票1").start();
        new Thread(web,"抢票2").start();
        new Thread(web,"抢票3").start();
    }
}

运行效果:

(5)实现Callable接口完成多线程(了解)

一般在高并发编程中才用。

Callable接口特点:

  1.   Callable规定的方法是call(),而Runnable规定的方法是run(). 
  2.   Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。  
  3.   call()方法可抛出异常,而run()方法是不能抛出异常的。 
  4.   运行Callable任务可拿到一个Future对象, Future表示异步计算的结果。 
  5.   它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。 
  6.   通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值