JAVA关于多线程的学习

news2024/10/6 10:43:09

1.创建线程的方法(这里不考虑继承Thread类)

通过实现Runnable接口的方式实现

public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName()+"执行了....");
        }
    }
}

public class Test01 {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);// 也可以直接写匿名类
        thread.start();

        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName()+"执行了....");
        }
    }
}

2.同步代码块

同一个时间,只有一个线程可以运行,锁住
注意,必须是同一把锁,当然,由于基本数据类型的特殊性,有些基本数据类型也是可以锁住的,比如 Integer = (0-127) 之内是可以充当锁的,当然,锁只能锁住使用他的线程。

1.格式

synchronized(任意对象){
可能出现线程安全的代码
}

2.代码

public class Test {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        Thread t1 = new Thread(ticket, "赵四");
        Thread t2 = new Thread(ticket, "广坤");
        Thread t3 = new Thread(ticket, "刘能");

        //开启线程
        t1.start();
        t2.start();
        t3.start();
    }
}
public class Ticket implements Runnable{
    int ticket = 100;

    //创建一个对象充当锁对象
    Object obj = new Object();
    @Override
    public void run() {
        while(true){
            try {
                Thread.sleep(100L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (obj){
                if (ticket>0){
                    System.out.println(Thread.currentThread().getName()+"买了第"+ticket+"张票");
                    ticket--;
                }

            }
        }
    }
}

3.同步方法

1.介绍

关键字是synchrosnized 锁 this
所以,runnable的实现类要是同一个对象
或者使用static方法 这时候锁就是 类.class

2.代码块

public class Ticket implements Runnable {
    int ticket = 100;

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(100L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            method();
        }
    }
  /*  public synchronized void method() {
        if (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + "买了第" + ticket + "张票");
            ticket--;
        }

    }*/

    public void method() {
        synchronized (this){
            if (ticket > 0) {
                System.out.println(Thread.currentThread().getName() + "买了第" + ticket + "张票");
                ticket--;
            }
        }


    }
}

4.关于对一个类的不同业务的思考

如果对一个类的不同业务处理,应该怎么处理呢?
线程如果对一个类进行操作,或者根据一个类的数据进行相应的方法调用?
首先第一点,必须要拿到这个类的数据,所以,必须要拿到这个类的对象,或者是这个类的子类。

  1. 将业务方法写在类中,然后通过类的对象进行调用
  2. 将业务方法写在线程类中,线程类中存一个类的对象。

1.包子铺代码

做一个卖一个

//包子铺代码 操作对象
public class BaoZiPu {

        //定义一个count证明生产包子,消费包子
        private int count;
        //定义一个flag,证明有没有包子
        private boolean flag;

        public BaoZiPu() {
        }

        public BaoZiPu(int count, boolean flag) {
            this.count = count;
            this.flag = flag;
        }

        //专门给消费线程服务
        public void getCount() {
            System.out.println("消费了第"+count+"个包子...........");
        }

        //专门给生产线程服务
        public void setCount() {
            count++;
            System.out.println("生产了第"+count+"个包子....");
        }

        public boolean isFlag() {
            return flag;
        }

        public void setFlag(boolean flag) {
            this.flag = flag;
        }

}
//  实现类 
public class Consumer implements Runnable{
    private BaoZiPu baoZiPu;
    public Consumer(BaoZiPu baoZiPu){
        this.baoZiPu = baoZiPu;
    }
    @Override
    public void run() {
        while(true){
            try {
                Thread.sleep(100L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (baoZiPu){
                //如果flag等于false.证明没有包子,消费线程等待
                if (baoZiPu.isFlag() == false){
                    try {
                        baoZiPu.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                //如果flag为true,证明有包子,消费包子,然后唤醒生活线程
                baoZiPu.getCount();
                //改变flag状态为false,证明没有包子了
                baoZiPu.setFlag(false);
                //唤醒生产线程
                baoZiPu.notify();
            }
        }
    }
}
public class Product implements Runnable{
    private BaoZiPu baoZiPu;
    public Product(BaoZiPu baoZiPu){
        this.baoZiPu = baoZiPu;
    }
    @Override
    public void run() {
        while(true){
            try {
                Thread.sleep(100L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (baoZiPu){
                //如果flag等于true.证明有包子,生产线程等待
                if (baoZiPu.isFlag() == true){
                    try {
                        baoZiPu.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                //如果flag为false,证明没有包子,生产包子,然后唤醒消费线程
                baoZiPu.setCount();
                //改变flag状态为true,证明有包子了
                baoZiPu.setFlag(true);
                //唤醒消费线程
                baoZiPu.notify();
            }
        }
    }
}
 public static void main(String[] args) throws Exception{
        BaoZiPu baoZiPu = new BaoZiPu();
        Thread t1 = new Thread(new Product(baoZiPu));
        Thread t2 = new Thread(new Consumer(baoZiPu));
        t1.start();
        t2.start();



    }

问题:
1.为什么wait不能放在最后执行

while(true){
            try {
                Thread.sleep(100L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (baoZiPu){
                //如果flag等于true.证明有包子,生产线程等待
                if (baoZiPu.isFlag() == true){
                //如果flag为false,证明没有包子,生产包子,然后唤醒消费线程
                baoZiPu.setCount();
                //改变flag状态为true,证明有包子了
                baoZiPu.setFlag(true);
                //唤醒消费线程
                baoZiPu.notify();
                 try {
                        baoZiPu.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
            }
            }
        }

因为notify是将线程唤醒,线程是跟着wait继续走的,这时候直接循环,但是,如果拿到锁却拿不到条件,直接卡死在这里了
在这里插入图片描述

2.多生产多消费的包子铺

notifyAll 但是这样还是消耗资源比较严重,因为有可能出现多次重复拿到锁但是无法运行放弃锁,并且有些拿不到锁的也唤醒了.

public class BaoZiPu {
    //定义一个count证明生产包子,消费包子
    private int count;
    //定义一个flag,证明有没有包子
    private boolean flag;

    public BaoZiPu() {
    }

    public BaoZiPu(int count, boolean flag) {
        this.count = count;
        this.flag = flag;
    }

    //专门给消费线程服务
    public synchronized void getCount() {
        //如果flag等于false.证明没有包子,消费线程等待
        while (flag == false) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //如果flag为true,证明有包子,消费包子,然后唤醒生活线程
        System.out.println("消费了第" + count + "个包子...........");
        //改变flag状态为false,证明没有包子了
        flag = false;
        //唤醒生产线程
        this.notifyAll();
    }

    //专门给生产线程服务
    public synchronized void setCount() {
        //如果flag等于true.证明有包子,生产线程等待
        while (flag == true) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //如果flag为false,证明没有包子,生产包子,然后唤醒消费线程
        count++;
        System.out.println("生产了第" + count + "个包子....");
        //改变flag状态为true,证明有包子了
        flag = true;
        //唤醒消费线程
        this.notifyAll();
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}
public class Consumer implements Runnable{
    private BaoZiPu baoZiPu;
    public Consumer(BaoZiPu baoZiPu){
        this.baoZiPu = baoZiPu;
    }
    @Override
    public void run() {
        while(true){
            try {
                Thread.sleep(100L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            baoZiPu.getCount();
        }
    }
}
public class Product implements Runnable{
    private BaoZiPu baoZiPu;
    public Product(BaoZiPu baoZiPu){
        this.baoZiPu = baoZiPu;
    }
    @Override
    public void run() {
        while(true){
            try {
                Thread.sleep(100L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
              baoZiPu.setCount();
        }
    }
}
public class Test01 {
    public static void main(String[] args) {
        //创建包子铺对象
        BaoZiPu baoZiPu = new BaoZiPu();

        Product product = new Product(baoZiPu);

        Consumer consumer = new Consumer(baoZiPu);

        //两个生产线程
        new Thread(product).start();
        new Thread(product).start();

        //两个消费线程
        new Thread(consumer).start();
        new Thread(consumer).start();
    }
}

5.Lock

1. 介绍

   Lock lock = new ReentrantLock();
   lock.lock();// 加锁
   lock.unlock(); // 解锁

6.condition阻塞队列

 void await() ->线程等待  // 让当前线程等等
    void signal()->线程唤醒 // 从队列中唤醒一个等待线程
    Condition condition = lock.newCondition();

可以分业务唤醒队列,一个队列一个业务

1.包子例题

public class BaoZiPu {
    //定义一个count证明生产包子,消费包子
    private int count;
    //定义一个flag,证明有没有包子
    private boolean flag;

    //创建Lock对象
    Lock lock = new ReentrantLock();
    //为生产者创建Condition对象
    Condition productCondition = lock.newCondition();
    //为消费者创建Condition对象
    Condition consumerCondition = lock.newCondition();

    public BaoZiPu() {
    }

    public BaoZiPu(int count, boolean flag) {
        this.count = count;
        this.flag = flag;
    }

    //专门给消费线程服务
    public  void getCount() {
        //获取锁
        lock.lock();

        //如果flag等于false.证明没有包子,消费线程等待
        while (flag == false) {
            try {
                //消费线程等待
                consumerCondition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //如果flag为true,证明有包子,消费包子,然后唤醒生活线程
        System.out.println("消费了第" + count + "个包子...........");
        //改变flag状态为false,证明没有包子了
        flag = false;
        //唤醒生产线程
        productCondition.signal();

        //释放锁
        lock.unlock();
    }

    //专门给生产线程服务
    public  void setCount() {
        //获取锁
        lock.lock();
        //如果flag等于true.证明有包子,生产线程等待
        while (flag == true) {
            try {
                //生产线程等待
                productCondition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //如果flag为false,证明没有包子,生产包子,然后唤醒消费线程
        count++;
        System.out.println("生产了第" + count + "个包子....");
        //改变flag状态为true,证明有包子了
        flag = true;
        //唤醒消费线程
        consumerCondition.signal();

        //释放锁
        lock.unlock();
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}
public class Consumer implements Runnable{
    private BaoZiPu baoZiPu;
    public Consumer(BaoZiPu baoZiPu){
        this.baoZiPu = baoZiPu;
    }
    @Override
    public void run() {
        while(true){
            try {
                Thread.sleep(100L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            baoZiPu.getCount();
        }
    }
}
public class Product implements Runnable{
    private BaoZiPu baoZiPu;
    public Product(BaoZiPu baoZiPu){
        this.baoZiPu = baoZiPu;
    }
    @Override
    public void run() {
        while(true){
            try {
                Thread.sleep(100L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
              baoZiPu.setCount();
        }
    }
}
public class Test01 {
    public static void main(String[] args) {
        //创建包子铺对象
        BaoZiPu baoZiPu = new BaoZiPu();

        Product product = new Product(baoZiPu);

        Consumer consumer = new Consumer(baoZiPu);

        //两个生产线程
        new Thread(product).start();
        new Thread(product).start();

        //两个消费线程
        new Thread(consumer).start();
        new Thread(consumer).start();
    }
}

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

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

相关文章

基于.Net Core微服务-第1章:说明及技术栈

微服务是一种架构模式&#xff0c;提倡将单一应用程序划分为一组小的服务&#xff0c;服务相互协调、互相配合&#xff0c;为用户提供最终价值。

vulnhub-ripper(易)

打靶练习Ripper&#xff0c;这是一个中低的靶场 0x00 部署0x01 信息收集&#xff1a;端口扫描、服务发现0x02路径扫描0x03 总结 0x00 部署 靶机&#xff1a;下载地址 宿主机&#xff1a;kali2021版本 0x01 信息收集&#xff1a;端口扫描、服务发现 sudo arp-scan -l #探测存…

【每日随笔】摩托车驾驶 ④ ( 德州增驾摩托车 D 本记录 | 考场位置 “ 德州市公安局交警支队直属四大队车辆管理所 “ )

文章目录 一、进入考场二、科目一三、科目二1、推车 ( 找准车辆停放位置 )2、上车前检查 ( 开始考试前准备 )3、科目二考试开始4、科目二路线要求5、坡起6、绕桩7、单边桥 四、科目三教学1、推车 ( 找准车辆停放位置 )2、上车前检查 ( 开始考试前准备 )3、科目三考试开始4、科目…

NSS [SWPUCTF 2021 新生赛]Do_you_know_http

NSS [SWPUCTF 2021 新生赛]Do_you_know_http 先看题目&#xff0c;应该是伪造XFF&#xff0c;UA等东西。 postman一把梭。

Bootloader Design of PIC18 series MCU

注意&#xff1a;下列描述是在PIC单片机上启用Bootloader的一个相关知识的近似完备集。所有需要了解的&#xff0c;bootloader与用户态程序交互的理论知识都已给出。 1.概述 嵌入式产品化后&#xff0c;需要考虑现场升级&#xff0c;单片机如果需要添加现场升级功能&#xff…

linux+win——嵌套虚拟机性能测试

参考博文&#xff1a;CSDN-Violent-Ayang&#xff08;作者&#xff09;-UNIX BENCH详细安装及使用步骤 unix bench wget http://175.6.32.4:88/soft/test/unixbench/unixbench-5.1.2.tar.gz tar -xzvf unixbench-5.1.2.tar.gz cd unixbench-5.1.2 vim Makefile # 将 Makefile 中…

虹科方案 | Redis Enterprise:适用于任何企业的矢量数据库解决方案

用户希望他们遇到的每个应用程序和网站都具有搜索功能。然而&#xff0c;超过80%的业务数据是非结构化的&#xff0c;以文本、图像、音频、视频或其他格式存储。因此&#xff0c;我们需要一种跨非结构化数据的搜索方式。 什么是矢量数据库&#xff08;vector database&#xff…

【自动化测试教程】 —— pytest 框架详解 ~

pytest框架 特点: 容易上手, 入门简单, 文档丰富, 文档中有很多参考案例支持简单的单元测试和复杂的功能测试支持参数化执行测试用例过程中, 支持跳过操作支持重复失败的case支持运行Nose, unittest编写测试用例pytest支持很多第三方插件方便和持续集成工具集成 1. pytest断…

如何搭建独享的IP代理池?

随着互联网技术的日趋成熟&#xff0c;爬虫已经成为一种常见的数据获取方法。在采集业务中&#xff0c;建立本地IP代理池是非常重要的。今天将与您探讨IP代理池的选择以及如何搭建独享的IP代理池。 独享IP代理池是指由客户单独使用的IP池&#xff0c;优点是客户可以享受池中所…

关于opencv中cv2.imread函数读取的图像shape问题

图像坐标系是&#xff08;w,h&#xff09;,w为x轴&#xff0c;h为y轴,(x,y) 但opencv读出来的数组却正好相反&#xff0c;是&#xff08;h,w,3&#xff09;,(y,x,3) 所以这里会有一个转换 image cv2.imread(1.jpg) print(image.shape[0:2]) ##输出&#xff08;365,500&#x…

【操作系统】Linux编程 - 多线程的创建和使用 II (临界区 、互斥量、信号量的使用)

临界区的概念 之前的实例中我们只尝试创建了1个线程来处理任务&#xff0c;接下来让我们来尝试创建多个线程。 不过&#xff0c;还是得先拓展一个概念——“临界区” 临界区指的是一个访问共用资源&#xff08;例如&#xff1a;共用设备或是共用存储器&#xff09;的程序片段&…

哈工大计算机网络课程网络层协议详解之:Internet路由BGP协议详解

哈工大计算机网络课程网络层协议详解之&#xff1a;BGP协议详解 在之前的网络层协议中&#xff0c;我们介绍了Internet网络两个自治系统内的路由协议&#xff1a;RIP协议和OSPF协议。这两个协议应该来说是自治系统内协议的两个代表性协议&#xff0c;前一个基于距离向量路由算…

优化内存利用:深入了解垃圾回收算法与回收器

&#x1f52d; 大家好&#xff0c;我是 vnjohn&#xff0c;在互联网企业担任 Java 开发&#xff0c;CSDN 优质创作者 &#x1f4d6; 推荐专栏&#xff1a;Spring、MySQL、Nacos、Java&#xff0c;后续其他专栏会持续优化更新迭代 &#x1f332;文章所在专栏&#xff1a;JVM &am…

机器学习面试题- 特征工程

目录标题 1、为什么要对特征做归一化2、对特征归一化的方法2.1 线性函数归一化2.2 零均值归一化 3、对数据预处理时&#xff0c;如何处理类别型特征3.1 序号编码3.2 独热编码3.3 二进制编码 4、什么是组合特征&#xff1f;如何处理高维组合特征&#xff1f;5、怎样有效地找到组…

​python接口自动化(十)--post请求四种传送正文方式(详解)​

简介 post请求我在之前的文章已经讲过一部分了&#xff0c;主要是发送一些较长的数据&#xff0c;还有就是数据比较安全等。我们要知道post请求四种传送正文方式首先需要先了解一下常见的四种编码方式&#xff1a; HTTP 协议规定 POST 提交的数据必须放在消息主体&#xff08;…

SpringBoot处理全局异常详解(全面详细+Gitee源码)

前言&#xff1a;在日常的开发工作中&#xff0c;项目在运行过程中多多少少是避免不了报错的&#xff0c;对于报错信息肯定不可以把全部信息都抛给客户端去显示&#xff0c;这里就需要我们对常见的七种异常情况统一进行处理&#xff0c;让整个项目更加优雅。 目录 一、基本介绍…

AMEYA360:航顺芯片产品有哪些 航顺家族介绍

经济型 HK32M050 家族 采用ARM Cotex-M0内核&#xff0c;最新工艺标准&#xff0c;最高48M主频&#xff0c;内置16K FALSH&#xff0c;4K SRAM&#xff0c;支持DMA&#xff0c;内置4个模拟比较器&#xff0c;2路运放&#xff08;PGA&#xff09;&#xff0c;支持多种通讯包括2个…

二叉树 — 给定二叉树中某个节点,返回该节点的后继节点

后继节点定义&#xff1a; 二叉树以中序的方式进行遍历打印&#xff0c;节点X的下一个节点&#xff0c;就是X的后继节点。 假设二叉树如下图所示&#xff1a;则中序遍历的后打印出来的就是 4 -> 2 -> 5 -> 1 -> 6 -> 3 -> 7。如果X 3&#xff0c;则X的后继节…

Docker网络模型以及容器网络初探(一)

〇、前言 安装Docker时&#xff0c;它会自动创建三个网络&#xff0c;默认bridge网桥&#xff08;创建容器默认连接到此网络&#xff09;、 none 、host。各个方式有各自的特点&#xff0c;它们有着特定的差距&#xff0c;比如网络性能等&#xff0c;一般按照实际应用方式手动…

大数据之数据采集项目总结——hadoop,hive,openresty,frcp,nginx,flume

1、前期准备 2、数据收集 1、开启openresty&#xff0c;nginx和frcp内网穿透 2、编辑并启动定时器 3、查看是否收集到了数据 数据收集阶段结束&#xff0c;进入下一个阶段 2、将收集到的切分好的数据上传到hdfs 使用的工具&#xff1a;flume flume像一个管道一样&#xff0c…