JAVAV自学日志02(多线程)

进程(Process)和线程(Thread)的有什么何区别

定义

  1. 进程是具有一定独立功能的的程序,进程是系统进行资源分配和调度的一个独立单元。

  2. 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源

区别

  1. 一个程序至少有一个进程,一个进程至少有一个线程.
  2. 线程的划分尺度小于进程,使得多线程程序的并发性高。
  3. 进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
  4. 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是进程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
  5. 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。

普通方法调用和多线程

在这里插入图片描述

线程实现(重点)

继承Thread类(重点)
实现Runnable接口(重点)
实现Callable接口

线程的创建

1.继承Thread类(重点)

第一步:自定义线程类继承Thread类。
第二步:重写run()方法,编写线程执行体。
第三步:创建线程对象,调用start()方法启动线程。

package com.tjrac.demo01;
//第一步:自定义线程类继承Thread类。
//第二步:重写run()方法,编写线程执行体。
//第三步:创建线程对象,调用start()方法启动线程。方法启动线程
public class TestThread1 extends  Thread{
    @Override
    public void run() {
        for(int i=0;i<20;i++){
            System.out.println("我在看代码");
        }
    }

    public static void main(String[] args) {
        //创建线程对象
        TestThread1 testThread1=new TestThread1();
        //调用对象的start方法
        testThread1.start();
        for(int i=0;i<200;i++){
            System.out.println("我学习多线程"+i);
        }
    }
}

实战下载图片

package com.tjrac.demo01;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
//第一步:自定义线程类继承Thread类。
//第二步:重写run()方法,编写线程执行体。
//第三步:创建线程对象,调用start()方法启动线程。方法启动线程
public class TestThread1 extends  Thread{
    private String url;//网络图片的地址
    private String name;//保存的文件名
    public TestThread1(String url,String name){
        this.url=url;
        this.name=name;
    }
    //下载线程的执行体
    @Override
    public void run() {
        WedDownlaoder wedDownlaoder= new WedDownlaoder();
        wedDownlaoder.Downlaoder(url,name);
        System.out.println(name+"下载完成");
    }
    public static void main(String[] args) {

        //创建线程对象
        TestThread1 t1=new TestThread1("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1577168219347&di=5bb4508ef618b0da3aed3d042eb8997e&imgtype=0&src=http%3A%2F%2Fimaegs.creditsailing.com%2Farticle%2F121%2F57_ua3ao__.jpg","陈声铭用多线程下载的图片01.jpg");
        TestThread1 t2=new TestThread1("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1577168219347&di=5bb4508ef618b0da3aed3d042eb8997e&imgtype=0&src=http%3A%2F%2Fimaegs.creditsailing.com%2Farticle%2F121%2F57_ua3ao__.jpg","陈声铭用多线程下载的图片02.jpg");
        TestThread1 t3=new TestThread1("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1577168219347&di=5bb4508ef618b0da3aed3d042eb8997e&imgtype=0&src=http%3A%2F%2Fimaegs.creditsailing.com%2Farticle%2F121%2F57_ua3ao__.jpg","陈声铭用多线程下载的图片03.jpg");

        //调用对象的start方法
        t1.start();
        t2.start();
        t3.start();
    }
}
//下载器
class WedDownlaoder{
    //下载方法
    public void Downlaoder(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("Downlaoder方法异常");
        }
    }
}

总结:线程开启不一定执行,由CPU调度执行,不推荐用Thread类,因为要不免单继承的局限性。

2.实现Runnable接口(重点)

第一步:实现Runnable接口。
第二步:重写run()方法。
第三步:将线程执行的接口放入接口实现类。

package com.tjrac.demo01;
//第一步:实现Runnable接口。
//第二步:重写run()方法。
//第三步:将线程执行的接口放入接口实现类。


public class TestRunnable01 implements Runnable{
    @Override
    public void run() {
        for(int i=0;i<20;i++){
            System.out.println("下载完成");
        }
    }

    public static void main(String[] args) {
        //创建Runnable接口的实现类对象
        TestRunnable01 testRunnable = new TestRunnable01();
        //创建线程对象,通过线程对象来启动线程
        new Thread(testRunnable).start();
        for(int i=0;i<500;i++){
            System.out.println("下载完成"+i);
        }
    }
}

实战下载图片(荣耀战魂)

package com.tjrac.demo01;

import org.apache.commons.io.FileUtils;

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

public class TestRunnable02 implements Runnable{
    private String url;//网络图片的地址
    private String name;//保存的文件名
    public TestRunnable02(String url,String name){
        this.url=url;
        this.name=name;
    }
    //下载线程的执行体
    @Override
    public void run() {
        RunnableDownlaoder runnableDownlaoder= new RunnableDownlaoder();
        runnableDownlaoder.Downlaoder(url,name);
        System.out.println(name+"下载完成");
    }
    public static void main(String[] args) {

        //创建线程对象
        TestRunnable02 t1=new TestRunnable02("https://imgsa.baidu.com/forum/pic/item/8a13632762d0f703b83556ae07fa513d2697c539.jpg","陈声铭用多线程下载的图片04.jpg");
        //调用对象的start方法
        new Thread(t1).start();
    }
}
//下载器
class RunnableDownlaoder{
    //下载方法
    public void Downlaoder(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("Downlaoder方法异常");
        }
    }
}

总结:推挤使用Runnable接口,方便灵活,可以一个对象被多个线程使用,但是会出现多线程并发的问题。在这里插入图片描述
多个线程同时操作一个对象实战
卖火车票

package com.tjrac.demo01;
//多个线程同时操作一个对象
//卖火车票
public class TestRunnable03 implements Runnable {
    private int ticket=10;
    @Override
    public void run() {
        //模拟延时
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        while (true) {
            if(ticket<=0){
                break;
            }
            System.out.println(Thread.currentThread().getName()+"买到了第"+ticket--+"票");
        }
    }

    public static void main(String[] args) {
        TestRunnable03 testRunnable03=new TestRunnable03();
        new Thread(testRunnable03,"陈声铭").start();
        new Thread(testRunnable03,"雷志明").start();
        new Thread(testRunnable03,"唐可明").start();
        new Thread(testRunnable03,"陈笑").start();
    }
}
3.实现Callable接口

在这里插入图片描述
实战下载图片

package com.tjrac.demo01;

import org.apache.commons.io.FileUtils;

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

public class TestCallable01 implements Callable<Boolean> {
    private String url;//网络图片的地址
    private String name;//保存的文件名
    public TestCallable01(String url,String name){
        this.url=url;
        this.name=name;
    }
    //下载线程的执行体
    @Override
    public Boolean call() {
        RunnableDownlaoder runnableDownlaoder= new RunnableDownlaoder();
        runnableDownlaoder.Downlaoder(url,name);
        System.out.println(name+"下载完成");
        return true;
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {

        //创建线程对象
        TestCallable01 t1=new TestCallable01("https://imgsa.baidu.com/forum/w%3D580%3B/sign=16a0044f35f33a879e6d0012f6671138/37d12f2eb9389b508c5b672d8a35e5dde7116e2d.jpg","陈声铭用多线程下载的图片05.jpg");
        //创建执行服务
        ExecutorService ser = Executors.newFixedThreadPool(1);
        //提交执行
       Future<Boolean> r1=ser.submit(t1);
        //获取结果
        boolean rs1=r1.get();
        //关闭服务器
        ser.shutdownNow();
    }
}
//下载器
class CallableDownlaoder{
    //下载方法
    public void Downlaoder(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("Downlaoder方法异常");
        }
    }
}

线程的5个状态

  1. new
  2. 就绪状态
  3. 运行状态
  4. 阻塞状态
  5. dead
    在这里插入图片描述
    在这里插入图片描述
    停止线程
    在这里插入图片描述
package com.kuang.springbootmybatis.controller;


public class TestRunnable03 implements Runnable {
    public boolean flag=true;
    @Override
    public  void run() {
        int ticket=0;
        while (flag) {
            System.out.println("Thread...run"+ticket++);
        }
    }
    public void stop(){
        this.flag=false;
    }
    public static void main(String[] args) {
        TestRunnable03 testRunnable03=new TestRunnable03();
        new Thread(testRunnable03).start();
        for (int i=0;i<=10000;i++){
            System.out.println("main"+i);
            if(i==9000){
                testRunnable03.stop();
                System.out.println("线程停止");
            }
        }
    }
}

线程休眠

  1. sleep指定当前线程阻塞速秒。
  2. sleep存在异常InterruptedException。
  3. sleep时间到达之后线程进入就绪状态。
  4. sleep可以用来模拟网络延时,倒计时等。
  5. 每一个对象都有一个锁,sleep不会释放锁。
package com.kuang;

import jdk.internal.dynalink.beans.StaticClass;

import java.text.SimpleDateFormat;
import java.util.Date;

public class TestSleep {
    public static void main(String[] args){
        Date data=new Date(System.currentTimeMillis());
        while(true){
            try {
                Thread.sleep(1000);
                System.out.println(new SimpleDateFormat("HH:mm:ss").format(data));
                data=new Date(System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
    //倒计时
    public static  void tenDown() throws InterruptedException {
        int num=10;
        while(true){
            Thread.sleep(1000);
            System.out.println(num--);;
            if(num<=0){
                break;
            }
        }
    }
}

线程礼让

  1. 礼让线程,让当前正在执行的线程暂停,但不阻塞。
  2. 将线程从运行状态转为就绪状态。
  3. 让cpu重新调度,礼让不一定成功!看CPU心情
package com.kuang;

public class TestYield {
    public static void main(String[] args){
        MyYield myYield=new MyYield();
        new Thread(myYield,"a").start();
        new Thread(myYield,"b").start();
    }
}
//礼让
class MyYield implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"线程开始");
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+"线程结束");
    }
}

join

  1. join合并线程,待该线程执行完成后,再执行其他线程,其他线程阻塞。
  2. 就是插队
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值