【Java SE】基础知识回顾——【13.线程 | 同步】

news2024/11/19 2:27:50

【线程 同步】

第一章 Thread

1.1 Thread类

/**
 * @author 270
 *    获取线程的名称:
 *         1.使用Thread中的方法getName()
 *              String getName() 返回该线程的名称
 *         2.可以获取到当前正在执行的线程,使用线程中的方法getName()获取名称
 *              static Thread currentThread() 返回对当前正在执行的线程对象的引用
 *              输出格式:Thread[Thread-1,5,main]
 *
 *              (中括号中的三个数据分别为:正在执行线程,线程优先级,线程所属线程组)
 *
 */
/**1.定义Thread的子类
 * @author 270*/
public class MyThread extends Thread{
    /**2.重写run方法,设置线程任务*/
    @Override
    public void run() {
        /**用getName重写*/
        String name = getName();
        System.out.println(name);
       /**用currentThread重写*/
       /* Thread t = Thread.currentThread();
        System.out.println(t);*/
       /**链式编程*/
        System.out.println(Thread.currentThread().getName());
    }
}
package Demo01;

/**
 * @author 270
 *  线程名称:
 *     主线程:main
 *     新线程:Thread-0
 */
public class   Demo01GetThreadName {
    public static void main(String[] args) {
        /**创建Thread类子类对象*/
        MyThread myThread = new MyThread();
        /**开启新线程*/
        myThread.setName("厄斐琉斯");
        myThread.start();
        /**开启新线程*/
        new MyThread().start();
        new MyThread().start();
        new MyThread().start();
        new MyThread().start();
        new MyThread().start();
        /**链式编程获取主线程名称*/
        System.out.println(Thread.currentThread().getName());

    }
}

1.2 第二种创建线程的方法

/**
 * @author 270
 *         创建线程的第二种方式:实现Runnable接口
 *          java.lang.Runnable
 *             Runnable接口应该由那些打算通过某一线程执行其实例的类来实现
 *             类必须定义一个称为run的无参数方法
 *          java.lang.Thread类的构造方法
 *              Thread(Runnable target)分配新的Thread对象
 *              Thread(Runnable target,String name)分配新的Thread对象。
 *         实现步骤:
 *            1.创建一个Runnable接口的实现类
 *            2.在实现类中重写Runnable接口的run方法,设置线程任务
 *            3.创建Runnable接口的实现类对象
 *            4.创建Thread类对象,构造方法中传递Runnable接口的实现类对象
 *            5.调用Thread类中的start方法,开启新的线程执行run方法
 *
 */
public class Demo01Runnable {
    public static void main(String[] args) {
        /**3.创建Runnable接口的实现类对象*/
        RunnableImpl runnable = new RunnableImpl();
        /**4.创建Thread类对象,构造方法中传递Runnable接口的实现类对象*/
        Thread thread = new Thread(runnable);
        thread.start();
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }
    }
}

实现类

package Demo02;

/**
 * @author 270
 */
/**1.创建一个Runnable接口的实现类*/

public class RunnableImpl implements Runnable{
    @Override
   /** 2.在实现类中重写Runnable接口的run方法,设置线程任务*/
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }
    }
}
实现Runnable接口创建多线程程序的好处
*       1.避免了单继承的局限性
*          一个类只能继承一个类(一个人只能有亲爹),类继承了Thread类就不能继承其他的类
*          实现了Runnable接口,还可以继承其他的类,实现其他接口
*       2.增强了程序的扩展性,把设置线程任务和开启新线程进行了分离(解耦)
*          实现类中,重写了run方法,用来设置线程任务
*          创建Thread类对象,调用start方法,用来开启新线程

1.3匿名对象类实现线程创建

package Demo02;

/**
 * @author 270
 * 匿名内部类实现线程的创建
 *
 * 格式:
 *   new 父类/接口(){
 *       重复父类/接口中的方法
 *   };
 *   实现Runnable接口创建多线程程序的好处
 *       1.避免了单继承的局限性
 *          一个类只能继承一个类(一个人只能有亲爹),类继承了Thread类就不能继承其他的类
 *          实现了Runnable接口,还可以继承其他的类,实现其他接口
 *       2.增强了程序的扩展性,把设置线程任务和开启新线程进行了分离(解耦)
 *          实现类中,重写了run方法,用来设置线程任务
 *          创建Thread类对象,调用start方法,用来开启新线程
 */
public class Demo02InnerClass {
    public static void main(String[] args) {
        /**继承的匿名方法*/
        new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 20; i++) {
                    System.out.println(Thread.currentThread().getName());
                }
            }
        }.start();
        /**接口的匿名实现类简化版*/
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"270");
            }
        }).start();
    }



}

第二章 线程安全问题

2.1线程安全

2.2同步

在这里插入图片描述

三种方式实现同步操作:
1.同步代码块

2.同步方法

3.锁机制

2.3 同步代码块

同步代码块解决多线程安全问题:package Demo03;

/**
 * @author 270
 *   卖票问题出现的线程安全问题
 *   卖出不存在的票和重复的票
 *
 *   解决线程安全问题的一种方案:使用同步代码块
 *   格式:
 *    synchronized(锁对象){
 *        可能会出现线程安全问题的代码(访问了共享数据的代码)
 *    }
 *   【注意】:
 *       1.通过代码块中的锁对象,可以使用任意的对象
 *       2.但是必须保证多个线程使用的锁对象是同一个
 *       3.锁对象作用:
 *             把同步代码块锁住,只让一个线程在同步代码块中执行
 */
public class RunnableImpl implements Runnable {
      /**定义多个线程共享的票源*/
      private int ticket = 1000;
      /**创建锁对象*/
      Object object = new Object();
      /**设置线程任务:卖票*/
    @Override
    public void run() {
       while (true){
           /**同步代码块*/
           synchronized (object){
               /**判断票是否存在*/
               if(ticket>0){
                   try {
                       Thread.sleep(10);
                   }catch (InterruptedException e){
                       e.printStackTrace();
                   }
                   /**存在票,卖票*/
                   System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票");
                   ticket--;
               }
           }
           }
       }
    }

2.4 同步方法

package Demo03;

/**
 * @author 270
 * 卖票问题出现的线程安全问题
 * 卖出不存在的票和重复的票
 * <p>
 * 解决线程安全问题的第二种种方案:使用同步方法
 * 使用步骤:
 * 1.把访问了共享数据的代码抽取出来,放到一个方法中
 * 2.在方法上添加synchronized修饰符
 *
 * 同步方法也会把方法内部的代码锁住
 * 只让一个线程执行
 * 同步方法的对象是谁
 * 就是实现类对象 new RunnableImpl()
 * 也就是this
 */
public class RunnableImpl implements Runnable {
    /**
     * 定义多个线程共享的票源
     */
    private int ticket = 1000;
    /**
     * 创建锁对象
     */
    Object object = new Object();

    /**
     * 设置线程任务:卖票
     */
    @Override
    public void run() {
        while (true) {
            payTicket();
        }
    }
       /**
     * 静态同步方法(了解)
     * 将 public synchronized void payTicket()和ticket用static关键字修饰
     * private static int ticket = 1000;和public static synchronized void payTicket() {
     *
     * 同步静态方法的锁对象不是this
     * this是创建对象之后产生的,静态方法优先于对象
     * 静态方法的锁对象是本类的class属性——>class文件对象(反射)
     * 这里写Runnable.class
     * */

    /**
     * 定义一个同步方法
     */
    public synchronized void payTicket() {
        /**判断票是否存在*/
        //synchronized(this){
        if (ticket > 0) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            /**存在票,卖票*/
            System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票");
            ticket--;
        }
    }
    //}
}

2.5 Lock锁

package Demo04.Demo03;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author 270
 * 卖票问题出现的线程安全问题
 * 卖出不存在的票和重复的票
 * <p>
 * 解决线程安全问题的第三种种方案:使用Lock锁
 * java.util.concurrent.locks.lock接口
 * Lock实现提供比使用synchronized方法和语句可以获得的更广泛的锁定操作。
 * Lock接口中的方法:
 *      void lock()
 *      获得锁。
 *      void unlock()
 *      释放锁。
 *  java.util.concurrent.locks.ReentrantLock implements Lock接口
 *     使用步骤:
 *        1.在成员位置创建一个ReentrantLock对象
 *        2.在可能会出现安全问题的代码之前调用lock接口中的方法lock获取锁
 *        3.在可能会出现安全问题的代码之后调用lock接口中的方法unlock释放锁
 */
public class RunnableImpl implements Runnable {
    /**
     * 定义多个线程共享的票源
     */
    private  int ticket = 1000;
    /**1.在成员位置创建一个ReentrantLock对象*/
      Lock l = new ReentrantLock();

    @Override
    public void run() {
        while (true) {

           //判断票是否存在
            if(ticket>0){
                l.lock();
                try{Thread.sleep(10);
                    System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票");
                    ticket--;
                }catch (InterruptedException e){
                    e.printStackTrace();
                }finally {
                    l.unlock();//无论程序是否异常,都会把锁释放
                }

            }

        }
    }


}

try…catch…finally

try之前紧跟lock()方法

finally中第一行写unlock()方法

第三章 线程状态(详见pdf)

等待唤醒案例
package Demo05;

/**
 * @author 270
 * 等待唤醒案例:线程间的通信
 *   创建顾客线程(消费者):告知商品的种类和数量,调用wait方法,放弃cpu执行进入waitting状态
 *   创建一个老板线程(生产者):花5秒准备商品,准备好之后调用notify方法,唤醒顾客领取
 *
 *【注意】:
 *    老板和顾客必须使用同步代码块包裹起来,保证等待和唤醒只能有一个在执行
 *    同步使用的锁对象必须保证唯一
 *    只有锁对象才能用wait和notify方法
 *
 *   void wait()
 *   导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法。
 *
 *   void notify()
 *   唤醒正在等待对象监视器的单个线程。
 *   会继续执行wait方法之后的代码
 */
public class Demo01WaitAndNotify {
    public static void main(String[] args) {
        //创建锁对象
        Object obj = new Object();
        //创建一个顾客线程(消费者)
        new Thread(){
            @Override
            public void run() {
                //保证等待和唤醒线程只能有一个执行,所以需要使用同步技术
                synchronized (obj){
                    System.out.println("告知商品种类和数量");
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //唤醒之后执行的代码
                    System.out.println("商品已经准备好了,可以提取了");
                }
            }
        }.start();
        /**创建老板的线程*/
        new Thread(){
            @Override
            public void run() {
                    try {
                        Thread.sleep(5000);//花五秒做包子
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //保证等待和唤醒的线程只有一个在执行,使用同步技术
                synchronized (obj) {
                    System.out.println("老板5秒后准备好商品,准备好后告知顾客");
                    obj.notify();
                }
                }
            }.start();
        }
    }
package Demo05;

/**
 * @author 270
 *   进入到TimeWaiting(计时等待)
 *      方式一:使用sleep(long m)方法,毫秒值结束后线程睡醒进入Runnable状态
 *      方式二:使用wait(long m)方法,wait方法如果在毫秒值结束之后,还没有被notify唤醒就会自动醒来
 *
 *   唤醒的方法:
 *         void notify()
 *             唤醒正在等待对象监视器的单个线程。
 *         void notifyAll()
 *             唤醒正在等待对象监视器的所有线程。
 */
public class Demo02WaitAndNotify {
    public static void main(String[] args) {
        //创建锁对象
        Object obj = new Object();
        //创建一个顾客线程(消费者)
        new Thread(){
            @Override
            public void run() {
               while (true){
                   //保证等待和唤醒线程只能有一个执行,所以需要使用同步技术
                   synchronized (obj){
                       System.out.println("顾客一告知商品种类和数量");
                       try {
                           obj.wait(5000);//这里加入时间参数后就算老板没做好商品,也会执行唤醒代码
                       } catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                       //唤醒之后执行的代码
                       System.out.println("商品已经准备好了,顾客一可以提取了");
                       System.out.println("================");
                   }
               }
            }
        }.start();

        new Thread(){
            @Override
            public void run() {
                while (true){
                    //保证等待和唤醒线程只能有一个执行,所以需要使用同步技术
                    synchronized (obj){
                        System.out.println("顾客二告知商品种类和数量");
                        try {
                            obj.wait(5000);//这里加入时间参数后就算老板没做好商品,也会执行唤醒代码
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        //唤醒之后执行的代码
                        System.out.println("商品已经准备好了,顾客二可以提取了");
                        System.out.println("================");
                    }
                }
            }
        }.start();

        /**创建老板的线程*/
        new Thread(){
            @Override
            public void run() {
               while (true){
                   try {
                       Thread.sleep(5000);//花五秒做包子
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
                   //保证等待和唤醒的线程只有一个在执行,使用同步技术
                   synchronized (obj) {
                       System.out.println("老板5秒后准备好商品,准备好后告知顾客");
                      /* obj.notify();*/
                       /**唤醒所有等待的线程*/
                       obj.notifyAll();
                   }
               }
            }
        }.start();
    }

}

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

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

相关文章

【年度TikTok电商数据解析】火遍全网!出单率超高!这个产品会成为2024年卖家新宠吗?

随着大众对口腔健康越来越重视&#xff0c;消费者对漱口水、牙线、口腔清新剂等口腔卫生产品形成深度依赖。 当然&#xff0c;这一趋势对于我们TikTok爆款商机打造息息相关。 然而&#xff0c;在目前的口腔护理赛道&#xff0c;高露洁、宝洁、飞利浦等巨头盘踞&#xff0c;掌握…

Spring重要知识点

一、Spring中相关概念 1.IOC 控制反转 IoC&#xff08;Inverse of Control:控制反转&#xff09;是⼀种设计思想&#xff0c;就是将原本在程序中⼿动创建对象的控制权&#xff0c;交由Spring框架来管理。IoC 在其他语⾔中也有应⽤&#xff0c;并⾮ Spring 所独有。 IoC 容器…

政务服务场景为何要打造AI交互数字人?

随着Chat GPT兴起&#xff0c;越来越多服务场景通过AI交互数字人以多模态交互形式实现人机交互。如近日昆山市档案馆推出了AI交互数字人“昆兰”&#xff0c;数字人设置于市档案馆一楼大厅入口处&#xff0c;市民可以与AI交互数字人进行实时问答交流&#xff0c;了解总书记关于…

使用 Docker 部署 的WAF: 雷池社区版

Web应用防火墙&#xff08;WAF&#xff09;是保护网站不受恶意攻击的关键组件。 使用 Docker 部署雷池社区版&#xff0c;可以大大简化安全管理工作。 一、WAF 雷池社区版简介 雷池社区版是一种流行的开源 Web 应用防火墙&#xff0c;它提供基本的安全保护&#xff0c;如防止…

【C++】:STL序列式容器list源码剖析

一、list概述 总的来说&#xff1a;环形双向链表 特点&#xff1a; 底层是使用链表实现的&#xff0c;支持双向顺序访问 在list中任何位置进行插入和删除的速度都很快 不支持随机访问&#xff0c;为了访问一个元素&#xff0c;必须遍历整个容器 与其他容器相比&#xff0c;额外…

小蓝和小桥的挑战*

题目 import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);int t sc.nextInt();sc.nextLine();while(t-- > 0) {int n sc.nextInt();sc.nextLine();int[] a new int[n];for(int i0;i<n;i)a[i…

【码银送书第十一期】《自然语言生成SQL与知识图谱问答实战》

语义解析技术可以提高人机交互的效率和准确性&#xff0c;在自然语言处理、数据分析、智能客服、智能家居等领域都有广泛的应用前景。特别是在大数据时代&#xff0c;语义解析能够帮助企业更快速地从大量的数据中获取有用的信息&#xff0c;从而提高决策效率。 01 语义解析的应…

34、StoHisNet:CNN+Transformer结合首次用于胃病理图像4分类[奔狼怎配质疑雄狮!]

本文由贵州大学医学院&#xff0c;贵州省人民医院医学影像教研室&#xff0c;精密影像诊疗国际示范合作基地&#xff0c;贵州大学计算机科学与技术学院&#xff0c;清华大学北京信息科学与技术国家研究中心&#xff0c;共同合作&#xff0c;于2022年5月28日发表于<Computer …

我的最爱,人类的未来

ATLAS (Boston Dynamics&#xff1a;波士顿动力公司) Atlas是由波士顿动力公司设计的一种跳跃式、后空翻类人机器人&#xff0c;它使用深度传感器进行实时感知&#xff0c;并使用模型预测控制技术来改善运动。Atlas 高 5 英尺&#xff0c;重 190 磅&#xff0c;拥有三台机载计算…

VBA窗体跟随活动单元格【简易版】(2/2)

上一篇博客&#xff08;文章连接如下&#xff09;中使用工作表事件Worksheet_SelectionChange实现了窗体跟随活动单元格的动态效果。 VBA窗体跟随活动单元格【简易版】(1/2) 为了在用户滚动工作表窗体之后仍能够实现跟随效果&#xff0c;需要使用Application.Windows(1).Visibl…

数据结构Java版(3)——队列Queue

一、概念 队列也是一种线性数据结构&#xff0c;最主要的特点是入队列顺序和出队列顺序是相同的&#xff0c;操作时在队尾入队&#xff0c;在队首出队。在Java中给我们提供了一个泛型队列——Queue&#xff0c;其中最常用的方法有&#xff1a; void offer()&#xff1a;入队E …

Ubuntu下将nvidia-smi封装为GUI界面,实时查看显卡信息

和win系统不同的是&#xff0c;在Ubuntu端&#xff0c;系统级的系统监视器中&#xff0c;只能查看内存、CPU和网络状态&#xff0c;并不能查看GPU状态 而使用NVIDIA显卡的朋友都知道一条指令 nvidia-smi 在终端运行后即可查看显卡信息、资源占用情况等 但是这样会占用终端&am…

轮胎侧偏刚度线性插值方法

一、trucksim取数据 步骤一 步骤二 二、数据导入到matlab中 利用simulink的look up table模块 1是侧偏角&#xff1b;2是垂直载荷&#xff1b;输出是侧向力。 侧向力除以侧偏角就是实时的侧偏刚度。

排序:计数排序

目录 思想&#xff1a; 操作步骤&#xff1a; 思路&#xff1a; 注意事项&#xff1a; 优缺点&#xff1a; 代码解析&#xff1a; 完整代码展示&#xff1a; 思想&#xff1a; 计数排序又称为鸽巢原理&#xff0c;是对哈希直接定址法的变形应用。 操作步骤&#xff…

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK使用Binning像素合并功能(C#)

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK使用Binning像素合并功能&#xff08;C#&#xff09; Baumer工业相机Baumer工业相机NEOAPI SDK和短曝光功能的技术背景Baumer工业相机通过CameraExplorer软件使用Binning功能Baumer工业相机通过NEOAPI SDK使用Binning功能1.引用合…

2018年认证杯SPSSPRO杯数学建模C题(第二阶段)机械零件加工过程中的位置识别全过程文档及程序

2018年认证杯SPSSPRO杯数学建模 基于轮廓提取与图像配准的零件定位问题研究 C题 机械零件加工过程中的位置识别 原题再现&#xff1a; 在工业制造自动生产线中&#xff0c;在装夹、包装等工序中需要根据图像处理利用计算机自动智能识别零件位置&#xff0c;并由机械手将零件…

python数字图像处理基础(九)——特征匹配

目录 蛮力匹配&#xff08;ORB匹配&#xff09;RANSAC算法全景图像拼接 蛮力匹配&#xff08;ORB匹配&#xff09; Brute-Force匹配非常简单&#xff0c;首先在第一幅图像中选取一个关键点然后依次与第二幅图像的每个关键点进行&#xff08;描述符&#xff09;距离测试&#x…

爆推联盟,推广接单平台定制开发(智创有术)

爆推联盟官网、推广接单平台、很多朋友问我做项目要怎么做&#xff0c;项目怎么选&#xff1f;那些项目比较稳定靠谱&#xff0c;赚钱还不错的平台&#xff0c;其实网上的项目很多&#xff0c;别说做&#xff0c;看都看不过来&#xff0c;我们做项目最主要的就是稳定嘛&#xf…

智能化未来:NFC技术助力数字化社区

引言 数字化转型深刻改变着社区管理的方式&#xff0c;其中NFC技术作为一种近场通讯技术&#xff0c;正在为数字社区的智能化未来提供强有力的支持。 NFC技术简介 近场通讯技术(NFC)是一种无线通信技术&#xff0c;能够实现设备之间的近距离通讯。在数字社区建设中&#xf…

第一讲_HarmonyOS应用开发环境准备

HarmonyOS应用开发环境准备 1. 知识储备2. 环境搭建2.1 安装node.js2.2 配置node.js2.3 安装命令行工具2.4 安装DevEco Studio2.5 配置DevEco Studio 1. 知识储备 HarmonyOS提供了一套UI开发框架&#xff0c;即方舟开发框架&#xff08;ArkUI框架&#xff09;。方舟开发框架可…