当前位置: 首页 > article >正文

JAVA多线程学习

文章目录

    • 线程相关概念
    • 线程创建
      • 继承Thread类
      • Runnable接口
      • 多个线程同时操作同一个对象测试:
      • 实现callable接口(了解)
      • 静态代理
      • lamda表达式
    • 线程状态
        • 线程停止
        • 线程休眠
        • 线程礼让

线程相关概念

  • 线程:是进程的一部分,一个进程之内的线程之间共享进程的地址空间、资源。

  • 进程:一个进程可以包含干个线程,但至少有一个线程(线程是CPU调度和执行的单位)。每个进程有独立的地址空间、全局变量、系统资源。是系统资源分配的单位。

  • 多线程:一个进程中并发多个线程,每个线程执行不同任务。

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

相关概念

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

线程创建

三种创建方式:

  • Thread class(继承Thread类)
  • Runnable接口(实现Runnable接口)
  • Callable接口(实现Callable接口,了解即可)

继承Thread类

自定义线程类继承Thread类

重写run()方法,编写线程执行体

创建线程对象,调用start()方法启动线程

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

package ThreadStudy;
//继承Thread类
public class ThreadTest01 extends Thread{
    @Override
    public void run(){
        //run()方法线程体
        for(int i=0;i<10;i++){
            System.out.println("run"+i);
        }
    }

    public static void main(String[] args) {
        //main线程(主线程)
        //创建一个线程对象
        ThreadTest01 threadTest01 =new ThreadTest01();
        //调用start()方法开启线程
        threadTest01.start();

        for(int i=0;i<10;i++){
            System.out.println("主线程"+i);
        }
    }
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

总结:线程开启不一定立即执行,这个由CPU进行调度。

案例:下载图片

package ThreadStudy;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.security.spec.RSAOtherPrimeInfo;
//实现多线程同步下载图片
public class DownloadTest extends Thread{

    private String url;//图片地址
    private String name;//保存的文件名
    public DownloadTest(String url,String name){
        this.name=name;
        this.url=url;
    }
    @Override
    public void run(){
        webDownloader webDownloader=new webDownloader();
        webDownloader.downloader(url,name);
        System.out.println("下载了文件名为:"+name);
    }

    public static void main(String[] args) {
        DownloadTest t1=new DownloadTest("https://img30.360buyimg.com/security/jfs/t1/106812/11/17157/47913/5e859436E81f1efd9/c6c4cf56305d75d2.jpg","1.jpg");
        DownloadTest t2=new DownloadTest("https://img30.360buyimg.com/security/jfs/t1/100763/10/17328/48613/5e85946eEd153e514/8ffec9a8e7832567.jpg","2.jpg");
        DownloadTest t3=new DownloadTest("https://img30.360buyimg.com/security/jfs/t1/98816/36/17526/48339/5e8594a8E4e154c27/42afb9370b45dab5.jpg","3jpg");

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

//下载器
class webDownloader{
    //下载方法
    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方法出现问题");
        }
    }
}

可以看到下载不是按照顺序下载的

Runnable接口

定义MyRunnable类实现Rnnable接口

实现run()方法,编写线程执行体

创建线程对象,调用start()方法启动线程

package ThreadStudy;

public class TestRunnable implements Runnable{
    @Override
    public void run(){
        for(int i=0;i<10;i++){
            System.out.println("run"+i);
        }
    }

    public static void main(String[] args) {
        //创建runnable接口的实现类对象
        TestRunnable testRunnable=new TestRunnable();

        //创建线程对象,通过线程对象开启线程,代理
        //相当于:
        //Thread thread=new thread(testRunnable);\
        //thread.start();
        new Thread(testRunnable).start();

        for(int i=0;i<20;i++){
            System.out.println("main"+i);
        }
    }
}

使用Runnable接口实现下载图片:
只需要将继承Thread改为实现Runnable接口,再改一下start()部分即可

package ThreadStudy;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.security.spec.RSAOtherPrimeInfo;
//实现多线程同步下载图片
public class DownloadTest implements Runnable{

    private String url;//图片地址
    private String name;//保存的文件名
    public DownloadTest(String url,String name){
        this.name=name;
        this.url=url;
    }
    @Override
    public void run(){
        webDownloader webDownloader=new webDownloader();
        webDownloader.downloader(url,name);
        System.out.println("下载了文件名为:"+name);
    }

    public static void main(String[] args) {
        DownloadTest t1=new DownloadTest("https://img30.360buyimg.com/security/jfs/t1/106812/11/17157/47913/5e859436E81f1efd9/c6c4cf56305d75d2.jpg","1.jpg");
        DownloadTest t2=new DownloadTest("https://img30.360buyimg.com/security/jfs/t1/100763/10/17328/48613/5e85946eEd153e514/8ffec9a8e7832567.jpg","2.jpg");
        DownloadTest t3=new DownloadTest("https://img30.360buyimg.com/security/jfs/t1/98816/36/17526/48339/5e8594a8E4e154c27/42afb9370b45dab5.jpg","3jpg");

        new Thread(t1).start();
        new Thread(t2).start();
        new Thread(t3).start();
    }
}

//下载器
class webDownloader{
    //下载方法
    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方法出现问题");
        }
    }
}

小结:
继承Thread类

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

实现Runnable接口

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

多个线程同时操作同一个对象测试:

package ThreadStudy;
//多个线程同时操作同一个对象
//模拟买票的例子
//发现问题:多个线程操作同一个资源时,线程不安全,数据紊乱
public class ThreadTest01 implements Runnable{

    private int ticketNums=10;

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

    public static void main(String[] args) {
        //创建runnable接口的实现类对象
        ThreadTest01 ticket=new ThreadTest01();

        //创建线程对象,通过线程对象开启线程
        new Thread(ticket,"A").start();
        new Thread(ticket,"B").start();
        new Thread(ticket,"C").start();

    }
}

案例:龟兔赛跑

package ThreadStudy;
//模拟龟兔赛跑
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("rabbit")&&i%10==0){
                try{
                    Thread.sleep(1);
                }catch(Exception 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;
        }{
            if(steps>=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,"rabbit").start();
        new Thread(race,"turtle").start();
    }
}

实现callable接口(了解)

实现callable接口需要返回值类型

重写call方法,需要抛出异常

创建目标对象

创建执行服务:ExecutorService ser=Executors.newFixedThreadPool(1);

提交执行:Future result1=ser.submit(t1);

获取结果:boolean r1=result1.get()

关闭服务:ser.shutdownNow();

package ThreadStudy;

import org.apache.commons.io.FileUtils;

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

//实现多线程同步下载图片
public class TestCallable implements Callable<Boolean> {

    private String url;//图片地址
    private String name;//保存的文件名
    public TestCallable(String url,String name){
        this.name=name;
        this.url=url;
    }
    @Override
    public Boolean call(){
        webDownloader webDownloader=new webDownloader();
        webDownloader.downloader(url,name);
        System.out.println("下载了文件名为:"+name);
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        TestCallable t1=new TestCallable("https://img30.360buyimg.com/security/jfs/t1/106812/11/17157/47913/5e859436E81f1efd9/c6c4cf56305d75d2.jpg","1.jpg");
        TestCallable t2=new TestCallable("https://img30.360buyimg.com/security/jfs/t1/100763/10/17328/48613/5e85946eEd153e514/8ffec9a8e7832567.jpg","2.jpg");
        TestCallable t3=new TestCallable("https://img30.360buyimg.com/security/jfs/t1/98816/36/17526/48339/5e8594a8E4e154c27/42afb9370b45dab5.jpg","3jpg");

        //创建执行服务
        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();
    }
}

//下载器
class webDownloader{
    //下载方法
    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方法出现问题");
        }
    }
}

静态代理

package ThreadStudy;

//静态代理模式
public class StaticProxy {
    public static void main(String[] args) {
        WeddingCompany weddingcompany=new WeddingCompany(new You());
        weddingcompany.HappyMarry();
    }
}

interface Marry{
    void HappyMarry();
}

class You implements Marry{
    @Override
    public void HappyMarry(){
        System.out.println("happy");
    }
}

class WeddingCompany implements Marry{
    private Marry target;
    public WeddingCompany(Marry target){
        this.target=target;
    }
    @Override
    public void HappyMarry(){
        before();
        this.target.HappyMarry();
        after();
    }
    private void before(){
        System.out.println("结婚之前,布置现场");
    }
    private void after(){
        System.out.println("结婚之后,收尾款");
    }
}

静态代理总结:

真实对象和代理对象都要实现同一个目标,代理对象要代理真实角色

代理对象可以实现真实对象实现不了的功能,真实对象专注自己的功能

lamda表达式

为了避免匿名内部类定义过多,可以使代码看起来更简洁,其实质属于函数式编程。

**函数式接口定义:**只包含唯一一个抽象方法,那么它就是函数式接口。

public interface Runnable{
    public abstract vvoid run();
}

对于函数式接口,可以通过lamda表达式创建该接口的对象。

格式:

(params) -> expresssion[表达式]
    (params)->statement[语句]
    	(params)->{statements}
package lamda;

/*
推导lamda表达式
*/
public class TestLamda {

    //2、静态内部类
    static class Like2 implements ILike{
        @Override
        public void lamda(){
            System.out.println("test lamda2");
        }
    }

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

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

        //3、局部内部类
        class Like3 implements ILike{
            @Override
            public void lamda(){
                System.out.println("test lamda3");
            }
        }

        like=new Like3();
        like.lamda();

        //4、匿名内部类,没有类的名称,必须借助接口或父类
        like=new ILike(){
            @Override
            public void lamda(){
                System.out.println("test lamda4");
            }
        };
        like.lamda();

        //5、lamda简化
        like=()->{
            System.out.println("test lamda5");
        };
        like.lamda();

    }
}

//0、定义一个函数式接口
interface ILike{
    void lamda();
}

//1、实现类
class Like1 implements ILike{
    @Override
    public void lamda(){
        System.out.println("test lamda1");
    }
}

线程状态

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

线程方法

方法说明
setPriority(int new Priority)更改线程优先级
static void sleep(long millis)在指定的毫秒数内让当前正在执行的线程休眠
void join()等待该线程终止
static void yield()暂停当前正在执行的线程对象,并执行其他线程
void interrupt()中断线程(尽量别用这个方式)
boolean isAlive()测试线程是否处于活动状态
线程停止

尽量使线程自动停止(通过设置标记位)

线程休眠
线程礼让

线程强制执行

观测线程状态

线程优先级


http://www.kler.cn/a/504009.html

相关文章:

  • Wireshark抓包教程(2024最新版个人笔记)
  • 机器学习头歌(第三部分-强化学习)
  • fastadmin插件wanlshop使用方法
  • Anaconda安装(2024最新版)
  • C#,图论与图算法,输出无向图“欧拉路径”的弗勒里(Fleury Algorithm)算法和源程序
  • PCB印刷电路板快速上手04电容元件
  • TCP/UDP/IP报文大小
  • csp-j知识点:联合(Union)的基本概念
  • 解决问题 PHP $_SERVER[‘HTTPS‘] 没有值
  • WEB攻防-通用漏洞_XSS跨站_权限维持_捆绑钓鱼_浏览器漏洞
  • 【Java设计模式-4】策略模式,消灭if/else迷宫的利器
  • zabbix2.0
  • 22、PyTorch nn.Conv2d卷积网络使用教程
  • 在Spring中如何发布一个事件?
  • 懒汉式单例模式
  • 当当网热销书籍数据采集与可视化分析
  • 松散比较(PHP)(小迪网络安全笔记~
  • MySQL数据库(SQL分类)
  • WSL报错libcudnn_cnn_infer.so.8
  • 基于Hiperwalk的量子行走Python编程
  • 基于celery的任务管理,本文主要是处理自己的算法,暴露API,管理任务并发,多线程
  • LeetCode 2657. Find the Prefix Common Array of Two Arrays
  • SCDN跟高防IP相比哪个更好
  • 计算机视觉算法实战——实时车辆检测和分类(主页有相关源码)
  • 大语言模型训练的基本步骤解析
  • llama.cpp 模型可视化工具 GGUF Visualizer