栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

狂神说多线程笔记

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

狂神说多线程笔记

1.基本概念

Process和Thread

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

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

​ 一个进程可以包含有多个线程(如视频中同时听到声音、看到图像,还可以看弹幕)

​ 一个进程至少有一个线程,否则无存在的意义。

线程:CPU调度和执行的单位。

注意:很多多线程是模拟出来,真正的多线程是指有多个CPU,即多核,如服务器。如果是模拟出来的多线程,即在一个CPU的情况下,在同一个时间点,cpu只能执行一个代码,因为切换很快,所以就有同时执行的错觉。

2.核心概念
  • 线程就是独立的执行路径;

  • 在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程;

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

  • 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能认为干预的;

  • 对同一份资源操作时,会存在资源抢夺问题,需要加入并发控制;

  • 线程会带来额外的开销,如CPU调度时间,并发控制开销;

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

3.线程创建 1.继承Thread类,重写run方法 1.1创建Thread类 2.2重写run()方法 3.3调用start()开启线程
package com.xia.Thread;

public  class ThreadTest {

    // 继承 Thread 类并重写 run 方法
    public static class MyThread extends Thread{
        @Override
        public void run() {
         	for(int i=0;i<1000;i++){
        		System.out.println("狗尧来学Java");
    		}
        }
    }

    public static void main(String[] args) {
        //创建一个线程
        MyThread thread = new MyThread();
        //启动线程
        thread.start();
        for(int i=0;i<1000;i++){
        	System.out.println("杰哥是最帅的"+i);
    }
}

例如:
从网上下载图片保存在指定目录 
package com.xia.thread;

import org.apache.commons.io.FileUtils;

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

//练习Thread,使用多线程同步下载图片
public class ThreadTest1 extends Thread{

    private String url;//图片的网址。

    private String name;//图片的名字

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

    //线程的执行体
    @Override
    public void run() {
        WebDownLoader webDownLoader=new WebDownLoader();
        webDownLoader.downLoader(url,name,"C:\Users\xj\Desktop\照片\狗尧来");//下载到指定的地方,默认下载到根目录(最后图片会出现在桌面的’照片‘文件夹里,名为’狗尧来1.png‘)
        System.out.println("狗尧来,线程执行了"+name);

    }

    public static void main(String[] args) {
        ThreadTest1 t1=new ThreadTest1("https://i0.hdslb.com/bfs/bangumi/image/7131f7b273ec867918fac859dc32508153159b28.png@466w_260h.png","1.png");
        ThreadTest1 t2=new ThreadTest1("https://i0.hdslb.com/bfs/bangumi/image/93e371b87f50832c0aceace27ee09d5658bc8434.png@2560w_500h.png","2.png");
        ThreadTest1 t3=new ThreadTest1("https://i0.hdslb.com/bfs/bangumi/image/8096fa0ac5d1e0e81feb56dc757a44a8afa3d6f0.png@466w_260h.png","3.png");

        //多个线程同时进行,谁先下完谁最先打印
        t2.start();
        t1.start();
        t3.start();
    }
}

//下载器
class WebDownLoader{
    //下载方法
    public void downLoader(String url,String name,String savePath){
        try {
            URL url1=new URL(url);
            File file=new File(savePath+name);
            FileUtils.copyURLToFile(url1,file);//通过URL将图片保存在文件里面

        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("狗尧来,这个方法有问题");
        }
    }
}

2.实现Runnable接口 2.1实现Runnable接口 2.2重写run()方法 2.3执行线程需要创建runnable接口实现类,调用start()方法

代码:

package com.xia.thread;

public class ThreadTest2 implements Runnable{

    public void run() {
        for (int i=0;i<20;i++){
            System.out.println("狗尧来学Java"+i);
        }
    }

    public static void main(String[] args) {
        //创建Runnable接口的实现类
        ThreadTest2 test2 = new ThreadTest2();

        //创建线程对象,通过将runnable接口的实现类放入线程对象,来开启线程
        Thread thread = new Thread(test2);
        thread.start();
    }
}

例:模拟龟兔赛跑

package com.xia.thread;

public class Race implements Runnable{

    private static String winner;

    public void run() {
        for(int i=1;i<=100;i++){
            //显示走了多少步
            System.out.println(Thread.currentThread().getName()+"-->"+i);
            //判断比赛是否结束
            boolean is=isGameOver(i);
            if(is){
                break;
            }
        }
    }


    Boolean isGameOver(int i){
        //如果有winner就返回true
        if(winner!=null){
            return true;
        }
        if(i>=100){
            winner=Thread.currentThread().getName();
            System.out.println("winner is "+winner);
            return true;
        }
        return false;
    }

    public static void main(String[] args) {
        Race race=new Race();//一条赛道,两个线程。
        new Thread(race,"狗尧来").start();
        new Thread(race,"狗宗弟").start();
    }
}

结果如下:

D:Javabinjava.exe "-javaagent:C:UsersxjDesktopjava学习IntelliJ IDEA 2020.3.3libidea_rt.jar=51317:C:UsersxjDesktopjava学习IntelliJ IDEA 2020.3.3bin" -Dfile.encoding=UTF-8 -classpath D:Javajrelibcharsets.jar;D:Javajrelibdeploy.jar;D:Javajrelibextaccess-bridge-32.jar;D:Javajrelibextcldrdata.jar;D:Javajrelibextdnsns.jar;D:Javajrelibextjaccess.jar;D:Javajrelibextjfxrt.jar;D:Javajrelibextlocaledata.jar;D:Javajrelibextnashorn.jar;D:Javajrelibextsunec.jar;D:Javajrelibextsunjce_provider.jar;D:Javajrelibextsunmscapi.jar;D:Javajrelibextsunpkcs11.jar;D:Javajrelibextzipfs.jar;D:Javajrelibjavaws.jar;D:Javajrelibjce.jar;D:Javajrelibjfr.jar;D:Javajrelibjfxswt.jar;D:Javajrelibjsse.jar;D:Javajrelibmanagement-agent.jar;D:Javajrelibplugin.jar;D:Javajrelibresources.jar;D:Javajrelibrt.jar;C:UsersxjIdeaProjectsJedis01targetclasses;C:Usersxj.m2repositoryredisclientsjedis3.2.0jedis-3.2.0.jar;C:Usersxj.m2repositoryorgslf4jslf4j-api1.7.25slf4j-api-1.7.25.jar;C:Usersxj.m2repositoryorgapachecommonscommons-pool22.6.2commons-pool2-2.6.2.jar;C:Usersxj.m2repositorycomalibabafastjson1.2.62fastjson-1.2.62.jar;C:Usersxj.m2repositorycommons-iocommons-io2.4commons-io-2.4.jar com.xia.thread.Race
狗宗弟-->1
狗尧来-->1
狗宗弟-->2
狗尧来-->2
狗宗弟-->3
狗尧来-->3
狗宗弟-->4
狗尧来-->4
狗宗弟-->5
狗尧来-->5
狗宗弟-->6
狗尧来-->6
狗宗弟-->7
狗尧来-->7
狗尧来-->8
狗宗弟-->8
狗尧来-->9
狗宗弟-->9
狗尧来-->10
狗宗弟-->10
狗尧来-->11
狗宗弟-->11
狗尧来-->12
狗尧来-->13
狗尧来-->14
狗宗弟-->12
狗尧来-->15
狗宗弟-->13
狗尧来-->16
狗宗弟-->14
狗尧来-->17
狗尧来-->18
狗尧来-->19
狗尧来-->20
狗宗弟-->15
狗尧来-->21
狗尧来-->22
狗宗弟-->16
狗尧来-->23
狗宗弟-->17
狗尧来-->24
狗宗弟-->18
狗尧来-->25
狗尧来-->26
狗尧来-->27
狗宗弟-->19
狗尧来-->28
狗宗弟-->20
狗尧来-->29
狗宗弟-->21
狗尧来-->30
狗宗弟-->22
狗尧来-->31
狗宗弟-->23
狗尧来-->32
狗宗弟-->24
狗尧来-->33
狗宗弟-->25
狗尧来-->34
狗宗弟-->26
狗尧来-->35
狗宗弟-->27
狗宗弟-->28
狗尧来-->36
狗宗弟-->29
狗尧来-->37
狗尧来-->38
狗尧来-->39
狗宗弟-->30
狗尧来-->40
狗尧来-->41
狗尧来-->42
狗宗弟-->31
狗尧来-->43
狗尧来-->44
狗尧来-->45
狗尧来-->46
狗尧来-->47
狗宗弟-->32
狗尧来-->48
狗宗弟-->33
狗宗弟-->34
狗宗弟-->35
狗尧来-->49
狗宗弟-->36
狗尧来-->50
狗宗弟-->37
狗尧来-->51
狗宗弟-->38
狗宗弟-->39
狗宗弟-->40
狗宗弟-->41
狗宗弟-->42
狗宗弟-->43
狗宗弟-->44
狗尧来-->52
狗宗弟-->45
狗宗弟-->46
狗尧来-->53
狗宗弟-->47
狗尧来-->54
狗尧来-->55
狗宗弟-->48
狗尧来-->56
狗宗弟-->49
狗尧来-->57
狗尧来-->58
狗宗弟-->50
狗尧来-->59
狗尧来-->60
狗宗弟-->51
狗尧来-->61
狗宗弟-->52
狗尧来-->62
狗宗弟-->53
狗尧来-->63
狗宗弟-->54
狗尧来-->64
狗宗弟-->55
狗尧来-->65
狗宗弟-->56
狗尧来-->66
狗宗弟-->57
狗尧来-->67
狗宗弟-->58
狗尧来-->68
狗宗弟-->59
狗尧来-->69
狗宗弟-->60
狗尧来-->70
狗宗弟-->61
狗尧来-->71
狗尧来-->72
狗宗弟-->62
狗尧来-->73
狗宗弟-->63
狗尧来-->74
狗宗弟-->64
狗尧来-->75
狗宗弟-->65
狗尧来-->76
狗宗弟-->66
狗尧来-->77
狗宗弟-->67
狗尧来-->78
狗宗弟-->68
狗尧来-->79
狗宗弟-->69
狗尧来-->80
狗宗弟-->70
狗尧来-->81
狗宗弟-->71
狗宗弟-->72
狗尧来-->82
狗宗弟-->73
狗宗弟-->74
狗尧来-->83
狗宗弟-->75
狗尧来-->84
狗宗弟-->76
狗尧来-->85
狗宗弟-->77
狗尧来-->86
狗宗弟-->78
狗尧来-->87
狗宗弟-->79
狗尧来-->88
狗宗弟-->80
狗尧来-->89
狗宗弟-->81
狗尧来-->90
狗宗弟-->82
狗尧来-->91
狗尧来-->92
狗宗弟-->83
狗尧来-->93
狗尧来-->94
狗尧来-->95
狗宗弟-->84
狗宗弟-->85
狗宗弟-->86
狗尧来-->96
狗尧来-->97
狗宗弟-->87
狗尧来-->98
狗宗弟-->88
狗尧来-->99
狗宗弟-->89
狗尧来-->100
狗宗弟-->90
winner is 狗尧来

Process finished with exit code 0
以上两种方式的比较: 继承 Thread 类

1.子类继承 Thread 类具备多线程能力

  • 启动线程:子类对象 .start()
  • 不建议使用:避免 OOP 单继承局限性

2.实现 Runnable 接口

  • 实现接口 Runnable 具有多线程能力
  • 启动线程:传入目标对象+Thread对象.start()
  • 推荐使用:避免单继承局限性,方便同一个对象被多个线程使用。
3.实现Callable接口 1.实现Calleble接口 2.重写call()方法 3.创建执行服务
ExecutorService ser = Executors.newFixedThreadPool(线程数);

提交执行

Future<返回值类型> r = ser.submit(线程名);

获取结果

类型 res=r.get();

关闭服务

ser.shutdownNow();

总结:

优点:1.可以定义返回值;2.能抛出异常

​ 缺点:相比而言较为麻烦

狂神说多线程笔记

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/643092.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号