08.JAVA线程基础

news2024/9/27 15:34:18

1.线程介绍

单线程:同一个时刻,只允许执行一个线程

多线程:同一个时刻,允许执行多个线程

并发:同一时刻,多个任务交替执行。

并行:同一时刻,多个任务同时执行。

2.线程使用

方式一:继承Thread类,重写run方法

public class thread01 {
    public static void main(String[] args) {
        //创建Cat对象,可以当作线程使用
        Cat cat = new Cat();
        cat.start();//启动线程-->最终会执行cat的run方法
        //主线程main和子线程cat会交替执行,主线程不会阻塞
        //如果这里还有代码,也会执行,不是等到子线程执行完,才执行这里的代码
    }
}
class Cat extends Thread{
    //1.当一个类继承了thread类,该类就是线程类
    //Thread的run方法是实现Runnable接口的run方法
    int times=0;
    @Override
    public void run() {//重写run方法
        while (true){
            System.out.println("喵喵"+(++times)+"线程名称="+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);//毫秒=1秒
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if(times == 80){
                break;
            }
        }
    }
}

方式二:实现Runable接口,重写run方法(静态代理)

例1:Thread类代理

public class runnable02 {
    public static void main(String[] args) {
        T2 t2 = new T2();
        //这里不能直接调用star
        //创建一个Thread对象,把t2对象传入
        Thread thread=new Thread(t2);
        //底层是静态代理模式
        thread.start();
    }
}
class T2 implements Runnable{
    int count=0;
    @Override
    public void run() {
        while (true){
            System.out.println("修狗"+(count++));
            //休眠一秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

例2:Cat1类模拟Thread类的静态代理

public class runable {
    public static void main(String[] args) {
        Cat1 cat1=new Cat1();
        new Proxy(cat1).start();
    }
}
class Animal{}
class Cat1 extends Animal implements Runnable{

    @Override
    public void run() {
        System.out.println("猫咪");
    }
}
//模拟的Thread
class Proxy implements Runnable{
    private Runnable target=null;
    @Override
    public void run() {
        if (target!=null){
            target.run();
        }
    }

    public Proxy(Runnable target) {
        this.target = target;
    }
    public void start(){
        start0();
    }
    public void start0(){
       run();
    }
}

图竖着看 

Thread和Runnable 本质上没有区别,都是start()-->start0()-->run()。

Runnable接口更适合多个线程共享一个资源,避免了单继承的情况。

T3 t3 = new T3();
Thread thread1 = new Thread(t3);
Thread thread2 = new Thread(t3);
thread1.start();
thread2.start();

如何通知线程停止?

public class Thread03 {
    public static void main(String[] args) throws InterruptedException {
        T3 t3 = new T3();
        Thread thread1 = new Thread(t3);
        thread1.start();
        Thread.sleep(10 * 1000);//主线程休眠10秒,子线程还在一直跑
        t3.setLoop(false);//10秒之后,主线程恢复,通知子线程停止

    }
}
class T3 implements Runnable{
    private boolean loop=true;
    int n=10;
    @Override
    public void run() {
        while (loop){
            System.out.println("hello world"+(n++));
            try {
                Thread.sleep(1000);//子线程每隔1秒输出一次
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public void setLoop(boolean loop) {
        this.loop = loop;
    }
}

3.线程方法

常用方法第一组:
1.setName ()//设置线程名称,使之与参数 name 相同
2. getName ()//返回该线程的名称
·3.start() //使该线程开始执行; Java 虚拟机底层调用该线程的
4.run ()//调用线程对象 run 方法
5.setPriority() //更改线程的优先级
6.getPriority() //获取线程的优先级
7. sleep()//在指定的毫秒数内让当前正在执行的线程休眠
8. interrupt()//中断线程

public class ThreadMothd01 {
    public static void main(String[] args) throws InterruptedException {
        T t = new T();
        t.setName("qwq");
        t.setPriority(Thread.MAX_PRIORITY);
        t.start();

        //主线程打印5 hi,然后我就中断 子线程休眠
        for (int i = 0; i < 5; i++) {
            Thread.sleep(1000);
            System.out.println("hi"+i);
        }
        t.interrupt();

    }
}
class T extends Thread{
    @Override
    public void run() {
        while (true){
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName()+"吃饱了"+i);
            }
            System.out.println(Thread.currentThread().getName()+"休眠---");
            try {
                Thread.sleep(20000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName()+"唤醒了---");
        }

    }
}

 常用方法第二组:
1. yield():线程的礼让。让出cpu,让其他线程执行,但礼让的时间不确定,所以也不一定礼让成功。
2.join(): 线程的插队。插队的线程一旦插队成功,则肯定先执行完插入的线程所有的任务
案例: 创建一个子线程 ,每隔1s 输出 hello,输出 20次,主线程每隔1秒,输出 hi,输出 20次.要求: 两个线程同时执行,当主线程输出 5次后,就让子线程运行完毕,主线程再继续。

public class TreadMothed01 {
    public static void main(String[] args) throws InterruptedException {
        Hi hi = new Hi();
        hi.start();

        for (int i = 0; i < 20; i++) {
            System.out.println("hi");
            Thread.sleep(500);
            if(i==4){
                System.out.println("第五个");
                hi.join();
            }
        }
    }
}
class Hi extends Thread{
    private int n=0;

    @Override
    public void run() {
        while (true){
            System.out.println("hello");
            n=n+1;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if(n==20){
                break;
            }
        }

    }
}

 用户线程和守护线程 

1.用户线程:也叫工作线程,当线程的任务执行完结束或通知方式结束。
2.守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结束。

常见的守护线程: 垃圾回收机制。

如何设计一个守护线程?

答://先设置成守护线程,再启动,否则报错
hi.setDaemon(true);

public class TreadMothed01 {
    public static void main(String[] args) throws InterruptedException {
        Hi hi = new Hi();
        //如果我们希望主线程结束,子线程自动结束
        //把子线程设计成守护线程
        //先设置成守护线程,再启动,否则报错
        hi.setDaemon(true);
        hi.start();
        for (int i = 1; i <= 10; i++) {
            System.out.println("海贼王qwq");
            Thread.sleep(1000);
        }

    }
}
class Hi extends Thread{
    private int n=0;

    @Override
    public void run() {
        while (true){
            System.out.println("hello");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

    }
}

4.线程生命周期

5.Synchronized

使用同步访问技术,保证数据在任何同一时刻,最多有一个线程访问,以保证数据的完整性。 

具体实现方法-synchronized:

1.同步代码块
synchronized(对象){ // 得到对象的锁,才能操作同步代码
// 需要被同步代码;}
2.同步方法
public synchronized void m (String name)!
//需要被同步的代码

 注意事项和细节:
1.同步方法如果没有使用static修饰: 默认锁对象为this
2.如果方法使用static修饰,默认锁对象:当前类.class
3.实现的落地步骤
(1).需要先分析上锁的代码
(2).选择同步代码块或同步方法
(3).要求多个线程的锁对象为同一个即可!

public class spiao {
    public static void main(String[] args) {
        per per = new per();
        new Thread(per).start();
        new Thread(per).start();
        new Thread(per).start();


    }
}
//实现接口方式,使用synchronized实现线程同步
class per implements Runnable {//创建Runnable接口的实现类
    private int ticket = 50;
    private static boolean lop=true;//控制run方法变量
    Object o = new Object();

    //同步方法:静态
    //1.public synchronized static void m() {}
    //2.锁在per.class
    //3.也可以在代码块上写 synchronized ,同步代码块,锁是在类上
    public synchronized static void m1() {

    }
    public static void m2() {
        synchronized (per.class){
            System.out.println("aa");
        }
    }
    //同步方法:非静态
    //1.public synchronized void m() {}是一个同步方法
    //2.这时锁在 this 对象上
    //3.也可以在代码块上写 synchronized ,同步代码块,锁还是在this对象上
    public /*synchronized*/ void m() {//同一时刻,只有一个线程执行m方法
        synchronized (/*this*/ o) {
            if (ticket <= 0) {
                System.out.println("售票结束");
                lop = false;
                return;
            }
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("窗口还有" + (ticket--) + "票");
        }
    }

    @Override
    public void run() {
        while (lop) {
            m();
        }
    }
}

6.互斥锁

1.每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
2.关键字synchronized 来与对象的互斥锁联系。当某个对象用synchronized修饰时表明该对象在任一时刻只能由一个线程访问.
3.同步的局限性:导致程序的执行效率要降低
4.同步方法(非静态的)的锁可以是this,也可以是其他对象(要求是同一个对象)
5.同步方法(静态的)的锁为当前类本身

7.死锁

拿到a锁,才能拿b锁,然后执行代码

拿到b锁,才能拿a锁,然后执行代码

执行2个线程,一个拿到a锁,一个拿到b锁,都拿不到剩下的锁,就形成了死锁。

释放锁

1.当前线程的同步方法、同步代码块执行结束
2.当前线程在同步代码块,同步方法中遇到break、return.
3.当前线程在同步代码块,同步方法中出现了未处理的Error或Exception,导致异常结束
4.当前线程在同步代码块、同步方法中执行了线程对象的wait0方法,当前线程暂停,并释
放锁。

8.练习 

1.多线程执行

请编写一个程序,创建两个线程,一个线程每隔1秒输出“hello,world”,输出10
次,退出,一个线程每隔1秒输出“hi”,输出 5次退出。

public class Thread03 {
    public static void main(String[] args) {
        T3 t3 = new T3();
        T4 t4 = new T4();
        new Thread(t3).start();
        new Thread(t4).start();
        for (int i = 0; i < 5; i++) {
            System.out.println("主线程。。不会阻塞");
        }

    }
}
class T3 implements Runnable{
    int n=10;
    @Override
    public void run() {
        while (true){
            System.out.println("hello world"+(n++));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if (n==10){
                break;
            }
        }
    }
}
class T4 implements Runnable{
    int m=5;
    @Override
    public void run() {
        while (true){
            System.out.println("hi"+(m++));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if (m==5){
                break;
            }
        }
    }
}

2.

(1)在main方法中启动两个线程
(2)第1个线程循环随机打印100以内的整数
(3) 直到第2个线程从键盘读取了“Q”命令

public class e1 {
    public static void main(String[] args) {
        A a = new A();
        B b = new B(a);//传Q入a才能控制a
        a.start();
//输完Q之后按回车,才会把Q传给k
        b.start();

    }
}
class A extends Thread{
    private  boolean loop=true;

    public  void setLoop(boolean loop) {
        this.loop = loop;
    }

    @Override
    public void run() {
        while (loop){
            System.out.println( (int) (Math.random()*100) + 1 );
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
class B extends Thread{
    private A a;
    private Scanner scanner = new Scanner(System.in);
   public B(A a){
       this.a=a;
   }
    @Override
    public void run() {
        while (true){
            System.out.println("请输入字符。。。");
            char k = scanner.next().toUpperCase().charAt(0);
            if(k == 'Q'){
                a.setLoop(false);//a线程退出
                break;//b线程也退出
            }
        }
    }
}

3.

2个人同时取10000块钱,每次取1000,不能超取

public class e2 {
    public static void main(String[] args) {
        User user = new User();
        new Thread(user).start();
        new Thread(user).start();
    }
}
class User implements Runnable{
    private int num=10000;

    @Override
    public  void run() {
        while (true){
            synchronized (this){//那个线程获取到this锁,就执行代码块
                //得不到的就阻塞
                if(num>=1000){
                    num=num-1000;
                    System.out.println(Thread.currentThread().getName()+"取1000"+"当前余额"+num);
                }else {
                    System.out.println("没钱了");
                    break;
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }

        }
    }
}


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1981070.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

对称二叉树 - 力扣(LeetCode)C语言

101. 对称二叉树 - 力扣&#xff08;LeetCode&#xff09;(点击前面链接即可查看题目) 一、题目 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true示例 2&#xff1a; 输入&…

【有手就行】:从无到有搭建前端VUE项目

前言 由于好久没正儿八经写过前端代码了&#xff0c;导致现在想自己创建个VUE项目搞点东西却连步骤都忘了。反正闲着也是闲着&#xff0c;就简单归纳下&#xff0c;就当整理下笔记吧。 直接开始吧 本次教程主要以VUE 2.x版本为介绍 第一步 环境准备 1.安装Node 从 Node官网…

战绩绿油油!全红婵巴黎奥运再度爆火,一个家庭兴旺的底层逻辑——早读(逆天打工人爬取热门微信文章解读)

上期点赞挺多呀&#xff0c;看来周六不上班的人真不少&#xff0c;羡慕呀&#xff01; 引言Python 代码第一篇 洞见 全红婵巴黎奥运再度爆火&#xff0c;我顿悟一个家庭兴旺的底层逻辑第二篇 股市 绿油油战纪结尾 引言 今天很晚 没办法 今天上班都差点迟到 有两点 一是早上开始…

CodeSys中处理(拼接)超长字符串

文章目录 1.需求2.目前的限制3.解决方案4.注意事项4.1.更改字符串的长度后还是被限制在32767或者32768 1.需求 目前有个需求&#xff1a;在CodeSys中&#xff0c;需要将上万甚至十几万条数据&#xff08;字符串&#xff09;汇总到一个字符串上。 2.目前的限制 我们知道默认使…

8–9月,​Sui Move智能合约工作坊将在台北举行

你对区块链和去中心化应用感兴趣吗&#xff1f;想深入学习Sui Move编程语言吗&#xff1f; 从8月10日到9月28日&#xff0c;Sui Mover社区将在每周六下午13:00–17:00举办精彩的工作坊&#xff0c;为期两个月&#xff0c;带你从零基础入门到高级进阶&#xff0c;全面掌握Sui M…

Gateway网关设置请求头乱码

问题描述&#xff1a; ​ 在做gateway用户认证过程中&#xff0c;我们将前端传过来的token字符串进行解析以后&#xff0c;将用户信息存入请求头往下传递的过程中&#xff0c;如果用户信息中存在中文&#xff0c;下游服务从请求头中获取到用户信息时会出现乱码 ​ 总体来说&a…

担心异构数据库迁移踩“坑”?听听大咖们怎么说

在技术升级和国产化战略的双重推动下&#xff0c;如何将来自Oracle、MySQL等异构数据库的数据无缝迁移至国产数据库&#xff0c;已成为企业持续发展的关键一环。 YashanDB Meetup第13期特别邀请首届迁移体验官用户代表、TechTalk社区创始人尚雷&#xff0c;YashanDB 售后服务负…

【python】Scrapy中常见的“Response Not Ready”或“Response Not 200”错误分析及解决

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

家用洗地机有什么推荐的吗?洗地机口碑榜前四名推荐

随着日常清洁需求的提升&#xff0c;如今洗地机已成为现代家居清洁的好帮手&#xff0c;承担着家庭卫生的重要角色&#xff0c;而一台高效、便捷的洗地机更是成为了众多家庭清洁卫生必备工具。 不过市场上的洗地机品牌众多&#xff0c;每个品牌下又有诸多系列&#xff0c;让人…

动态规划之——背包DP(入门篇)

文章目录 概要说明01背包模板例题题意概要思路code1code2 01背包的应用题题目来源思路code 完全背包模板例题题意概要思路code 概要说明 本文只讲了01背包和完全背包&#xff0c;至于其他背包问题后续补充 01背包 模板例题 点击这里 题意概要 思路 01背包的模板题 首先对…

SAM 图像分割算法计算物体表面积

参考: https://enpeicv.com/forum.php?mod=viewthread&tid=90&extra=page%3D1 使用SAM算法进行图像分割,计算出分割图像有多少像素,然后根据像素数量计算实际面积 SAM安装及模型下载: https://github.com/facebookresearch/segment-anything?tab=readme-ov-file…

Gemini Pro 加持,谷歌 AI 笔记 Notebook LM 重磅升级!

在现在这种信息爆炸的时代&#xff0c;如何高效处理海量信息&#xff0c;已经成为困扰很多人的难题。如何整合来自不同来源的信息和想法&#xff0c;并在它们之间建立联系。这个过程&#xff0c;费时费力&#xff0c;还很容易让人抓狂&#xff0c;更别提还要从中提炼、归纳、整…

工作助手C#研究笔记(5)

通过示例对C#程序的结构逻辑进行研究梳理&#xff0c;虽然通过阅读相关书籍&#xff0c;但是来的效果更慢。一下相关内容可能有误&#xff0c;请谨慎听取。 TaskToDoList-master 1.XAML “XAML”是WPF中专门用于设计UI的语言&#xff0c;优点是 1.XAML可以设计出专业的UI和…

c# .Net Core 项目配置SWagger UI 带Token访问

简介 Swagger是一款强大的API管理工具&#xff0c;它主要用于生成、描述、调用和可视化RESTful风格的Web服务。Swagger通过一套标准的规范定义接口及其相关信息&#xff0c;从而能够自动生成各种格式的接口文档&#xff08;如HTML、PDF、Markdown等&#xff09;&#xff0c;并…

知识库、微调、AI Agent

Agent执行工作的过程是需要大模型来配合的&#xff0c;大模型充当一个大脑&#xff0c;给Agent下达指令。Agent当接收到这个指令的时候&#xff0c;然后去执行。 大模型参数的数量直接影响大模型的生成能力和推理能力&#xff0c;也直接影响了大模型的使用效果。参数越多&…

【竞技宝】奥运会:日本U23惨败梦想破裂

奥运会男足8进4的比赛已经全部结束,夺冠热门阿根廷被东道主法国淘汰,埃及点球淘汰巴拉圭,摩洛哥4比0大胜美国,亚洲球迷关心的日本U23竟然惨败西班牙U23,让不少球迷都觉得意外。因为日本U23赛前被普遍看好,可是他们却被西班牙队全面压制,甚至毫无还手之力,这样的结果让球迷们不禁…

【linux】linux中定时任务的巧妙运用,让你轻松解放双手

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全…

书生·共学计划|训练营又开始啦!

&#x1f970; 在大模型技术的浪潮中&#xff0c;面对混杂的众多信息&#xff0c;如何获取有效、可信的学习资源成为了一项挑战。为此&#xff0c;我们推出“书生共学计划”&#xff0c;鼓励大家将实战营活动分享给你身边有需要的小伙伴&#xff0c;让每一位热爱技术的朋友都能…

无人机培训机构开办投资收益分析

一、引言 随着无人机技术的飞速发展及其在航拍、农业、测绘、物流等多个领域的广泛应用&#xff0c;市场对无人机专业人才的需求急剧增长。因此&#xff0c;开设无人机培训机构成为了一个具有广阔市场前景的投资项目。本报告旨在全面分析无人机培训机构开办的投资收益&#xf…

面向开发者的 LLM 入门教程-笔记和代码

本文是 DLAI 课程 ChatGPT Prompt Engineering for Developers 的笔记。这门课面向入门 LLM 的开发者&#xff0c;深入浅出地介绍了如何构造 Prompt 并基于 OpenAI 提供的 API 实现包括总结、推断、转换等功能&#xff0c;是入门 LLM 开发的经典教程。 Prompt&#xff08;提示…