返回顶部
首页 > 资讯 > 后端开发 > Python >Java多线程学习笔记
  • 811
分享到

Java多线程学习笔记

2024-04-02 19:04:59 811人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

目录多任务、多线程程序、进程、线程学着看jdk文档线程的创建1.继承Thread类2.实现Runable接口理解并发的场景龟兔赛跑场景实现callable接口理解函数式接口理解线程的

多任务、多线程

在多任务场景下,两件事看上去同时在做,但实际上,你的大脑在同一时间只做一件事,间隔时间可能很少,但这似乎让你感觉这两件事是同时在做

考虑阻塞问题,引入多线程的场景,多线程并发场景

在这里插入图片描述

程序、进程、线程

程序=指令+数据(静态的)
操作系统中运行的程序就是进程,一个进程可以有多个线程
比如,看视频时听声音,看图像,看弹幕等

学着看jdk文档

比如你要看Thread
你可以搜索,然后阅读

在这里插入图片描述

往下翻你会看到:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

线程的创建

1.继承Thread类


//创建线程方式一:继承Thread类,重写run方法,调用start()方法开启线程
public class TestThread1  extends Thread{

    @Override
    public void run() {
        //run()方法线程体
        IntStream.range(0,20).forEach(i->{
            System.out.println("我在看代码"+i);
        });
    }

    public static void main(String[] args) {
        //创建一个线程对象
        TestThread1 testThread1=new TestThread1();
        //调用start()方法,启动线程,不一定立即执行,由cpu调度执行
        testThread1.start();

        //主方法 main方法
        IntStream.range(0,20).forEach(i->{
            System.out.println("我在学习多线程"+i);
        });
    }
}

一个小练习:


//练习thread实现对线程同步下载图片
public class TestThread2 extends Thread{

    private String url;
    private String name;

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

    @Override
    public void run() {
          WEBDownload webDownload=new WebDownload();
          webDownload.downloader(url,name);
          System.out.println("下载了文件名:"+name);
    }

    public static void main(String[] args) {
        TestThread2 t1=new TestThread2("https://profile.csdnimg.cn/B/D/2/3_sxh06","1.jpg");
        TestThread2 t2=new TestThread2("Https://profile.csdnimg.cn/B/D/2/3_sxh06","2.jpg");
        TestThread2 t3=new TestThread2("https://profile.csdnimg.cn/B/D/2/3_sxh06","3.jpg");

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

    }
}

//下载器
class WebDownload{
    //下载方法
    public void downloader(String url,String name)  {
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (ioException e) {
            e.printStackTrace();
            System.out.println("IO异常,downloader方法出错");
        }
    }
}

2.实现Runable接口


//创建线程的方法2:实现Runable接口
public class TestThread3 implements Runnable{

    @Override
    public void run() {
        //run()方法线程体
        IntStream.range(0,20).forEach(i->{
            System.out.println("我在看代码"+i);
        });
    }

    public static void main(String[] args) {
        //创建一个线程对象
        TestThread3 testThread3=new TestThread3();
        //调用start()方法,启动线程,不一定立即执行,由cpu调度执行
//        Thread thread=new Thread(testThread3);
//        thread.start();

        //或者这样简写
       new Thread(testThread3).start();
        //主方法 main方法
        IntStream.range(0,100).forEach(i->{
            System.out.println("我在学习多线程"+i);
        });
    }
}

在这里插入图片描述

理解并发的场景

当多个线程使用同一个资源时,会出现问题,看看下面这个买火车票的例子:


public class TestThread4 implements  Runnable{

    //票数
    private int ticketNums=10;

    @Override
    public void run() {
        while(true){
            if (ticketNums<=0){
                break;
            }
            //模拟延迟
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketNums--+"张票");
        }

    }

    public static void main(String[] args) {
        TestThread4 ticket=new TestThread4();

        new Thread(ticket,"小明").start();
        new Thread(ticket,"张三").start();
        new Thread(ticket,"李四").start();
    }
}

看看运行的结果:

在这里插入图片描述

可以看到案例中的线程不安全问题,同时数据也是不正确的

龟兔赛跑场景



public class Race implements Runnable{
    //胜利者
    private static String winner;

    @Override
    public void run() {


        for (int i=0;i<=100;i++){
            //模拟兔子休息
            if (Thread.currentThread().getName().equals("兔子")&&i%10==0){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            boolean flag=gameOver(i);
            if (flag){  //判断比赛是否结束
               break;
            }
            System.out.println(Thread.currentThread().getName()+"-->跑了"+i+"步");
        }

    }

    
    private boolean gameOver(int steps){
        //判断是否有胜利者
        if (winner !=null){
            //已经存在胜利者
            return true;
        }else if (steps >= 100){
            winner=Thread.currentThread().getName();
            System.out.println("胜利者是:"+winner);
            return true;
        }else{
            return false;
        }
    }

    public static void main(String[] args) {
        Race race=new Race();
        new Thread(race,"兔子").start();
        new Thread(race,"乌龟").start();
    }
}

实现callable接口


//线程创建方式3
public class TestCallable implements Callable<Boolean> {
    private String url;
    private String name;

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

    @Override
    public Boolean call() {
        com.sxh.thread.WebDownload webDownload=new com.sxh.thread.WebDownload();
        webDownload.downloader(url,name);
        System.out.println("下载了文件名:"+name);
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        TestCallable t1=new TestCallable("https://profile.csdnimg.cn/B/D/2/3_sxh06","1.jpg");
        TestCallable t2=new TestCallable("https://profile.csdnimg.cn/B/D/2/3_sxh06","2.jpg");
        TestCallable t3=new TestCallable("https://profile.csdnimg.cn/B/D/2/3_sxh06","3.jpg");

        //创建执行服务
        ExecutorService ser= Executors.newFixedThreadPool(3);
        //提交执行
        Future<Boolean> r1=ser.submit(t1);
        Future<Boolean> r2=ser.submit(t2);
        Future<Boolean> r3=ser.submit(t3);
        //获取结果
        boolean rs1=r1.get();
        boolean rs2=r2.get();
        boolean rs3=r3.get();
        //关闭服务
        ser.shutdownNow();
    }

}

理解函数式接口

任何接口,只包含唯一一个抽象方法,就是函数式接口



public class TestLambda1 {
    //3.静态内部类
    static class Like2 implements ILike{
        @Override
        public void lambda() {
            System.out.println("i like lambda2");
        }
    }

    public static void main(String[] args) {
        ILike like=new Like();
        like.lambda();

        like=new Like2();
        like.lambda();

        //4.局部内部类
       class Like3 implements ILike{
            @Override
            public void lambda() {
                System.out.println("i like lambda3");
            }
        }
        like=new Like3();
        like.lambda();

        //5.匿名内部类
        like=new ILike() {
            @Override
            public void lambda() {
                System.out.println("i like lambda4");
            }
        };
        like.lambda();

        //6.用lambda简化
        like=()->{
            System.out.println("i like lambda5");
        };
        like.lambda();
    }
}

//1.定义一个函数式接口
interface ILike{
    void lambda();
}

//2.实现类
class Like implements ILike{

    @Override
    public void lambda() {
        System.out.println("i like lambda");
    }
}

理解线程的状态

在这里插入图片描述

线程停止


public class TestStop implements Runnable{

    //1.设置一个标志位
    private boolean flag=true;
    @Override
    public void run() {
       int i=0;
       while (flag){
           System.out.println("run...thread.."+i++);
       }
    }

    //2.设置一个公开的方法停止线程,转换标志位
    public void stop(){
           this.flag=false;
    }


    public static void main(String[] args) {
        TestStop stop=new TestStop();
        new Thread(stop).start();


        for (int i = 0; i < 1000; i++) {
            System.out.println("main"+i);
            if (i==900){
                //调用stop方法,让线程停止
                stop.stop();
                System.out.println("线程该停止了");
            }
        }
//        IntStream.range(0,1000).forEach(i->{
//            
//        });
    }
}

线程休眠sleep

每个对象都有一把,sleep不会释放锁

1.网路延迟


            //模拟延迟
            try {
                Thread.sleep(200); //ms
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

2.倒计时等


 public static void main(String[] args) {
       try {
            tendown();
        } 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;
            }
        }
    }

 public static void main(String[] args) {
        //打印系统当前时间
        Date startTime=new Date(System.currentTimeMillis());
        while (true){
            try {
                Thread.sleep(1000);
                System.out.println(new SimpleDateFORMat("HH:mm:ss").format(startTime));
                startTime=new Date(System.currentTimeMillis());//更新时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

线程礼让yield


//线程礼让  礼让不一定成功,由cpu重新调度
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方法  想象为插队
public class TestJoin implements  Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("线程vip来了"+i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        //启动线程
        TestJoin testJoin=new TestJoin();
        Thread thread=new Thread(testJoin);
        thread.start();

        //主线程
        for (int i = 0; i < 1000; i++) {
            if (i==200){
                thread.join(); //插队
            }
            System.out.println("main"+i);
        }
    }
}

观察线程状态


public class TestState {
    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("//");
        });

        //观察状态
        Thread.State state=thread.getState();
        System.out.println(state);   //NEW

        //启动后
        thread.start();
        state=thread.getState();
        System.out.println(state);   //Run

        while (state != Thread.State.TERMINATED)
        {
            Thread.sleep(100);
            state=thread.getState();//更新线程状态
            System.out.println(state);   //Run
        }
    }
}

线程的优先级


//测试线程的优先级
public class TestPriority {
    public static void main(String[] args) {
        //主线程默认优先级
        System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority());

        MyPriority myPriority=new MyPriority();

        Thread t1=new Thread(myPriority);
        Thread t2=new Thread(myPriority);
        Thread t3=new Thread(myPriority);
        Thread t4=new Thread(myPriority);
        Thread t5=new Thread(myPriority);
        Thread t6=new Thread(myPriority);
        //先设置优先级,在启动
        t1.start();
        t2.setPriority(1);
        t2.start();
        t3.setPriority(4);
        t3.start();
        t4.setPriority(Thread.MAX_PRIORITY);
        t4.start();
        t5.setPriority(-1);
        t5.start();
        t6.setPriority(11);
        t6.start();

    }
}
class MyPriority implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority());
    }
}

守护线程

线程分为用户线程和守护线程


//测试守护线程
public class TestDaemon {
    public static void main(String[] args) {
        God god=new God();
        You you=new You();
        Thread thread=new Thread(god);
        thread.setDaemon(true); //默认是false表示用户线程
        thread.start();

        new Thread(you).start();

    }
}

class God implements  Runnable{

    @Override
    public void run() {
      while (true){
          System.out.println("上帝保佑着你");
      }
    }
}
class You implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 36000; i++) {
            System.out.println("你活着"+i);
        }
        System.out.println("goodbye!!");
    }
}

线程同步机制

解决安全性问题:队列+锁

1.synchronized 同步方法

默认锁的是this,如需锁其他的,使用下面的同步块


//synchronized 同步方法
    private  synchronized void buy(){
        if (ticketNums<=0){
            flag=false;
            return;
        }
        //模拟延迟
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //买票
        System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketNums--+"张票");
    }

2.同步块synchronized(Obj){}

锁的对象是变化的量,需要增删改的对象
obj称之为同步监视器,即监视对象


public class UnsafeList {
    public static void main(String[] args) {
        List<String> list=new ArrayList<String>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                synchronized (list){
                    list.add(Thread.currentThread().getName());
                }
            }).start();
        }

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}

lock


class A{
     //ReentrantLock 可重入锁
     private final ReentrantLock lock=new ReentrantLock();
     public void f(){
       lock.lock();//加锁
       try{
           //.....
        }
       finally{
          lock.unlock();//释放锁
        }
     }
   
}


synchronized与lock

  1. lock是显示锁需要手动开关,synchronized是隐式锁,出了作用域自动释放
  2. lock只有代码块锁,synchronized有代码块锁和方法锁
  3. JVM将花费更少的时间来调度线程,性能更好,更有扩展性
  4. 优先使用:Lock>同步代码块>同步方法

到此这篇关于Java多线程学习笔记的文章就介绍到这了,更多相关Java 多线程内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Java多线程学习笔记

本文链接: https://lsjlt.com/news/137275.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Java多线程学习笔记
    目录多任务、多线程程序、进程、线程学着看jdk文档线程的创建1.继承Thread类2.实现Runable接口理解并发的场景龟兔赛跑场景实现callable接口理解函数式接口理解线程的...
    99+
    2024-04-02
  • Python学习笔记之线程
    目录1.自定义进程2.进程与线程3.多线程4.Thread类方法5.多线程与多进程小Case6.Thread 的生命周期7.自定义线程8.线程共享数据与GIL(全局解释器锁)9.GI...
    99+
    2024-04-02
  • JAVA编程学习笔记
    常用代码、特定函数、复杂概念、特定功能……在学习编程的过程中你会记录下哪些内容?快来分享你的笔记,一起切磋进步吧! 一、常用代码 在java编程中常用需要储备的就是工具类。包括封装的时间工具类。htt...
    99+
    2023-09-03
    java 学习 笔记
  • Java学习随记之多线程编程
    Process和Thread 程序是指令和数据的有序集合, 本身没有运行的含义,是一个静态的概念。 进程是执行程序的一次执行过程,他是一个动态的概念,是系统资源分配的单位 一个进程中...
    99+
    2024-04-02
  • Python 爬虫学习笔记之多线程爬虫
    XPath 的安装以及使用 1 . XPath 的介绍 刚学过正则表达式,用的正顺手,现在就把正则表达式替换掉,使用 XPath,有人表示这太坑爹了,早知道刚上来就学习 XPath 多省事 啊。其实我个人认...
    99+
    2022-06-04
    爬虫 之多 线程
  • 学习java多线程
    目录介绍为什么需要多线程线程状态转换线程使用方式继承 Thread 类实现 Runnable 接口实现 Callable 接口同步代码---Runnable接口方式同步方法--Run...
    99+
    2024-04-02
  • Python 学习笔记 - 多进程和进程
    前面学习了多线程,接下来学习多进程的创建和使用。多进程更适合计算密集型的操作,他的语法和多线程非常相像,唯一需要注意的是,多线程之间是可以直接共享内存数据的;但是多进程默认每个进程是不能访问其他进程(程序)的内容。我们可以通过一些特殊的方式...
    99+
    2023-01-31
    进程 学习笔记 Python
  • Python学习记录-多进程和多线程
    [TOC] 1. 进程和线程 进程 狭义定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed)。广义定义:进程是一个具有一定独立功能的程序关于某...
    99+
    2023-01-31
    多线程 进程 Python
  • JAVA学习笔记- - - day 2
     💕前言:作者是一名正在学习JAVA的初学者,每天分享自己的学习笔记,希望能和大家一起进步成长💕 目录  💕前言:作者是一名正在学习JAVA的初学者,每天分享自己的学习笔记,希望能和...
    99+
    2023-09-04
    学习
  • Java学习笔记之Maven篇
    目录一、maven能做什么?1.1 两大应用1.2 maven 的核心二、maven结构:2.1 maven工程标准目录结构2.2 配置系统变量2.3 常用命令三、应用:idea集成...
    99+
    2024-04-02
  • Java--内部类学习笔记
    本文介绍了什么是内部类,Java中的内部类:实例内部类. 静态内部类.局部内部类.匿名内部类的语法和注意事项,以及每个内部类的运用场景,以及简单介绍了匿名内部类更简洁更特殊的语法->lambda表...
    99+
    2023-09-11
    java 学习 笔记
  • Java Unsafe学习笔记分享
    目录sun.misc.Unsafe获取Unsafe实例重点API使用场景避免初始化内存崩溃(Memory corruption)抛出异常(Throw an Exception)大数组...
    99+
    2024-04-02
  • PHP学习笔记:在线教育与学习平台
    前言:随着互联网的不断发展,在线教育逐渐成为学习的一种新方式。越来越多的学生和学习者选择通过网络获取知识。而在线学习平台的搭建离不开强大的后台支持,而PHP作为一种成熟且功能强大的编程语言,被广泛应用于在线教育平台的开发中。功能需求:在搭建...
    99+
    2023-10-21
    在线教育 PHP 学习平台
  • 学习笔记-TP5框架学习笔记\(路由\)
    TP5框架简单理解 (PS:只做粗略、关键知识的记录,TP程序的开始。详情请阅读官方手册) 1. 架构总览 TP程序的开始 PHP >=5.3.0, PHP7 ThinkPHP5.0应用基于MVC(模型-视图-控制器)的方...
    99+
    2023-10-25
    学习 php 开发语言
  • Java 多线程学习总结3
    在上一篇中,我们当然希望a++,b++执行完之后,show方法再来show.我们需要的是“原子”动作,一次性地把a++,b++不间断地执行。在java中是利用“互斥”的方法,互斥谁呢?互斥的是相同对象的加锁代码。如果我们把第一篇的SomeB...
    99+
    2023-01-31
    多线程 Java
  • Java多线程Thread基础学习
    目录1. 创建线程   1.1 通过构造函数:public Thread(Runnable target, String name){}  或:publ...
    99+
    2023-05-17
    Java多线程 Java 多线程Thread
  • Hank的无线802.11学习笔记--p
    Technorati 标签: 802.11,无线,wifi,原理,基础 这里再说一下ESS的工作模式,其实最主要的就是漫游了。 保证已有的业务不中断. IP地址也不能变。如果IP变了就不叫漫游了,叫网络切换。 漫游也分为2层漫游和三层漫游...
    99+
    2023-01-31
    学习笔记 Hank
  • Python 爬虫学习笔记之单线程爬虫
    介绍 本篇文章主要介绍如何爬取麦子学院的课程信息(本爬虫仍是单线程爬虫),在开始介绍之前,先来看看结果示意图 怎么样,是不是已经跃跃欲试了?首先让我们打开麦子学院的网址,然后找到麦子学院的全部课程信息,像...
    99+
    2022-06-04
    爬虫 单线程 学习笔记
  • sqlite3 学习笔记
    #!/usr/bin/env python3 # -*- coding: utf-8 -*- # @descrip : operate SqLite intrface # @Time : 2020/04/22 21:57 # @Au...
    99+
    2017-12-28
    sqlite3 学习笔记 数据库入门 数据库基础教程
  • 20200618_MySQL学习笔记
    加号 + Mysql中加号只能做运算符 select 100+90  ==> 190  select "100"+90 ==> 190  如果有一个是字符串,那么尝试转换成数值型,转换成功 select "ja...
    99+
    2014-11-26
    20200618_MySQL学习笔记
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作