线程方法,生命周期,线程状态,Synchronized,

news2024/10/2 18:07:33
  1. package com.hspedu.method;
    
    /**
     * @author 韩顺平
     * @version 1.0
     */
    public class ThreadMethod01 {
        public static void main(String[] args) throws InterruptedException {
            //测试相关的方法
            T t = new T();
            t.setName("老韩");
            t.setPriority(Thread.MIN_PRIORITY);//设置优先级1
            t.start();//启动子线程
    
    
            //主线程打印5 hi ,然后我就中断 子线程的休眠
            for(int i = 0; i < 5; i++) {
                Thread.sleep(1000);
                System.out.println("hi " + i);
            }
    
            System.out.println(t.getName() + " 线程的优先级 =" + t.getPriority());//1
    
            t.interrupt();//当执行到这里,就会中断 t线程的休眠.
    
    
    
        }
    }
    
    class T extends Thread { //自定义的线程类
        @Override
        public void run() {
            while (true) {
                for (int i = 0; i < 100; i++) {
                    //Thread.currentThread().getName() 获取当前线程的名称
                    System.out.println(Thread.currentThread().getName() + "  吃包子~~~~" + i);
                }
                try {
                    System.out.println(Thread.currentThread().getName() + " 休眠中~~~");
                    Thread.sleep(20000);//20秒
                } catch (InterruptedException e) {
                    //当该线程执行到一个interrupt 方法时,就会catch 一个 异常, 可以加入自己的业务代码
                    //InterruptedException 是捕获到一个中断异常.
                    System.out.println(Thread.currentThread().getName() + "被 interrupt了");
                }
            }
        }
    }
    
    

    中断只中断一次

  2.  

    package com.hspedu.method;
    
    /**
     * @author 韩顺平
     * @version 1.0
     */
    public class ThreadMethod02 {
        public static void main(String[] args) throws InterruptedException {
    
            T2 t2 = new T2();
            t2.start();
    
            for(int i = 1; i <= 20; i++) {
                Thread.sleep(1000);
                System.out.println("主线程(小弟) 吃了 " + i  + " 包子");
                if(i == 5) {
                    System.out.println("主线程(小弟) 让 子线程(老大) 先吃");
                    //join, 线程插队
                    //t2.join();// 这里相当于让t2 线程先执行完毕
                    Thread.yield();//礼让,不一定成功..
                    System.out.println("线程(老大) 吃完了 主线程(小弟) 接着吃..");
                }
    
            }
        }
    }
    
    class T2 extends Thread {
        @Override
        public void run() {
            for (int i = 1; i <= 20; i++) {
                try {
                    Thread.sleep(1000);//休眠1秒
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("子线程(老大) 吃了 " + i +  " 包子");
            }
        }
    }
    
    
  3. 用户线程和守护线程

    1. 用户线程:也叫工作线程,当线程的任务执行完或通知方式结束

    2. 守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结

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

  4. package com.hspedu.method;
    
    /**
     * @author 韩顺平
     * @version 1.0
     */
    public class ThreadMethod03 {
        public static void main(String[] args) throws InterruptedException {
            MyDaemonThread myDaemonThread = new MyDaemonThread();
            //如果我们希望当main线程结束后,子线程自动结束
            //,只需将子线程设为守护线程即可
            myDaemonThread.setDaemon(true);
            myDaemonThread.start();
    
            for( int i = 1; i <= 10; i++) {//main线程
                System.out.println("宝强在辛苦的工作...");
                Thread.sleep(1000);
            }
        }
    }
    
    class MyDaemonThread extends Thread {
        public void run() {
            for (; ; ) {//无限循环
                try {
                    Thread.sleep(1000);//休眠1000毫秒
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("马蓉和宋喆快乐聊天,哈哈哈~~~");
            }
        }
    }
    
    
  5. 线程生命周期
  6. 线程状态。 线程可以处于以下状态之一:
    • NEW
      尚未启动的线程处于此状态。
    • RUNNABLE内核
      在Java虚拟机中执行的线程处于此状态。Ready【准备好了】和Running【真正的在执行】两个状态
    • BLOCKED
      被阻塞等待监视器锁定的线程处于此状态。
    • WAITING
      正在等待另一个线程执行特定动作的线程处于此状态。
    • TIMED_WAITING
      正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。
    • TERMINATED
      已退出的线程处于此状态。
  7. 线程同步机制
    • 在多线程编程,一些敏感数据不允许被多个线程同时访问,此时就使用同步访问技术,保证数据在任何同一时刻,最多有一个线程访问,以保证数据的完整性。
  8. 同步具体方法
    • 同步代码块
      synchronized(对象){//得到对象的锁,才能操作同步代码
          //需要被同步代码;
      }
      //synchronized还可以放在方法声明中,表示整个方法-为同步方法
      public synchronized void m1() {
      //需要被同步的代码
      
      }
  9. 互斥锁

    • java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性

    • 每个对象都对应一个可称为"互斥锁"的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。

    • 关键字synchronized来与对象的互斥锁联系。当某个对象用synchronized修饰时,表明该对象在任一时刻只能由一个线程访问

    • 同步的局限性:导致程序的执行效率要降低

    • 同步方法(非静态的)的锁可以是this,也可以是其他对象(要求是同一个对象)

    • 同步方法(静态的)的锁为当前类本身

  10. 互斥锁注意事项

    • 同步方法如果没有使用static修饰:默认锁对象为this

    • 如果方法使用static修饰,默认锁对象:当前类.class

    • 实现的落地步骤:

      • 需要先分析上锁的代码

      • 选择同步代码块或同步方法

      • 要求多个线程的锁对象为同一个即可!

  11. 解决售票不同步问题Synchronized
    • package com.hspedu.syn;
      
      /**
       * @author 韩顺平
       * @version 1.0
       * 使用多线程,模拟三个窗口同时售票100张
       */
      public class SellTicket {
          public static void main(String[] args) {
      
              //测试
      //        SellTicket01 sellTicket01 = new SellTicket01();
      //        SellTicket01 sellTicket02 = new SellTicket01();
      //        SellTicket01 sellTicket03 = new SellTicket01();
      //
      //        //这里我们会出现超卖..
      //        sellTicket01.start();//启动售票线程
      //        sellTicket02.start();//启动售票线程
      //        sellTicket03.start();//启动售票线程
      
      
      //        System.out.println("===使用实现接口方式来售票=====");
      //        SellTicket02 sellTicket02 = new SellTicket02();
      //
      //        new Thread(sellTicket02).start();//第1个线程-窗口
      //        new Thread(sellTicket02).start();//第2个线程-窗口
      //        new Thread(sellTicket02).start();//第3个线程-窗口
      
              //测试一把
              SellTicket03 sellTicket03 = new SellTicket03();
              new Thread(sellTicket03).start();//第1个线程-窗口
              new Thread(sellTicket03).start();//第2个线程-窗口
              new Thread(sellTicket03).start();//第3个线程-窗口
      
          }
      }
      
      
      //实现接口方式, 使用synchronized实现线程同步
      class SellTicket03 implements Runnable {
          private int ticketNum = 100;//让多个线程共享 ticketNum
          private boolean loop = true;//控制run方法变量
          Object object = new Object();
      
      
          //同步方法(静态的)的锁为当前类本身
          //老韩解读
          //1. public synchronized static void m1() {} 锁是加在 SellTicket03.class
          //2. 如果在静态方法中,实现一个同步代码块.
          /*
              synchronized (SellTicket03.class) {
                  System.out.println("m2");
              }
           */
          public synchronized static void m1() {
      
          }
          public static  void m2() {
              synchronized (SellTicket03.class) {
                  System.out.println("m2");
              }
          }
      
          //老韩说明
          //1. public synchronized void sell() {} 就是一个同步方法
          //2. 这时锁在 this对象
          //3. 也可以在代码块上写 synchronize ,同步代码块, 互斥锁还是在this对象
          public /*synchronized*/ void sell() { //同步方法, 在同一时刻, 只能有一个线程来执行sell方法
      
              synchronized (/*this*/ object) {///*synchronized*/把这的去掉了,加到这了
                  if (ticketNum <= 0) {
                      System.out.println("售票结束...");
                      loop = false;
                      return;
                  }
      
                  //休眠50毫秒, 模拟
                  try {
                      Thread.sleep(50);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
      
                  System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"
                          + " 剩余票数=" + (--ticketNum));//1 - 0 - -1  - -2
              }
          }
      
          @Override
          public void run() {
              while (loop) {
      
                  sell();//sell方法是一共同步方法
              }
          }
      }
      
      //使用Thread方式
      // new SellTicket01().start()
      // new SellTicket01().start();
      class SellTicket01 extends Thread {
      
          private static int ticketNum = 100;//让多个线程共享 ticketNum
      
      //    public void m1() {
      //        synchronized (this) {
      //            System.out.println("hello");
      //        }
      //    }
      
          @Override
          public void run() {
      
      
              while (true) {
      
                  if (ticketNum <= 0) {
                      System.out.println("售票结束...");
                      break;
                  }
      
                  //休眠50毫秒, 模拟
                  try {
                      Thread.sleep(50);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
      
                  System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"
                          + " 剩余票数=" + (--ticketNum));
      
              }
          }
      }
      
      
      //实现接口方式
      class SellTicket02 implements Runnable {
          private int ticketNum = 100;//让多个线程共享 ticketNum
      
          @Override
          public void run() {
              while (true) {
      
                  if (ticketNum <= 0) {
                      System.out.println("售票结束...");
                      break;
                  }
      
                  //休眠50毫秒, 模拟
                  try {
                      Thread.sleep(50);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
      
                  System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"
                          + " 剩余票数=" + (--ticketNum));//1 - 0 - -1  - -2
      
              }
          }
      }
      
      this是什么,SellTicket03.class又是什么
    • this是针对当前引用的对象,class对象就是原始对象本身
    • 非静态方法可以使用this或者class对象来同步,而静态方法必须使用class对象来同步并且它们互不影响
  12. 线程的死锁:多个线程都占用了对方的锁资源,但不肯让,导致死锁
  13. 释放锁

     

     

  14. 例题
    • package com.hspedu.homework;
      
      import java.util.Scanner;
      
      /**
       * @author 韩顺平
       * @version 1.0
       * 1.在main方法中启动两个线程
       * 2.第一个线程循环随机打印100以内的整数
       * 3.直到第2个线程从键盘读取了“Q”命令
       */
      public class Homework01 {
          public static void main(String[] args) {
              A a = new A();
              B b = new B(a);//一定要注意.
              a.start();
              b.start();
          }
      }
      
      //创建A线程类
      class A extends Thread {
          private boolean loop = true;
      
          @Override
          public void run() {
              //输出1-100数字
              while (loop) {
                  System.out.println((int)(Math.random() * 100 + 1));
                  //休眠
                  try {
                      Thread.sleep(1000);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
              System.out.println("a线程退出...");
      
          }
      
          public void setLoop(boolean loop) {//可以修改loop变量
              this.loop = loop;
          }
      }
      
      //直到第2个线程从键盘读取了“Q”命令
      class B extends Thread {
          private A a;//必须有这个属性
          private Scanner scanner = new Scanner(System.in);
      
          public B(A a) {//构造器中,直接传入A类对象
              this.a = a;
          }
      
          @Override
          public void run() {
              while (true) {
                  //接收到用户的输入
                  System.out.println("请输入你指令(Q)表示退出:");
                  char key = scanner.next().toUpperCase().charAt(0);
                  if(key == 'Q') {
                      //以通知的方式结束a线程
                      a.setLoop(false);
                      System.out.println("b线程退出.");
                      break;
                  }
              }
          }
      }
      

      创建线程,重写run方法,start(),获取字符,注意B类构造器的参数,属性

    • package com.hspedu.homework;
      
      /**
       * @author 韩顺平
       * @version 1.0
       */
      public class Homework02 {
          public static void main(String[] args) {
              T t = new T();
              Thread thread1 = new Thread(t);
              thread1.setName("t1");
              Thread thread2 = new Thread(t);
              thread2.setName("t2");
              thread1.start();
              thread2.start();
              //多线程创建对象是这样的
          }
      }
      
      //编程取款的线程
      //1.因为这里涉及到多个线程共享资源,所以我们使用实现Runnable方式
      //2. 每次取出 1000
      class T implements  Runnable {
          private int money = 10000;
      
          @Override
          public void run() {
              while (true) {
      
                  //解读
                  //1. 这里使用 synchronized 实现了线程同步
                  //2. 当多个线程执行到这里时,就会去争夺 this对象锁
                  //3. 哪个线程争夺到(获取)this对象锁,就执行 synchronized 代码块, 执行完后,会释放this对象锁
                  //4. 争夺不到this对象锁,就blocked ,准备继续争夺
                  //5. this对象锁是非公平锁.
      
                  synchronized (this) {//不是静态选this或者static修饰选类名.class。
                      //判断余额是否够
                      if (money < 1000) {
                          System.out.println("余额不足");
                          break;
                      }
      
                      money -= 1000;
                      System.out.println(Thread.currentThread().getName() + " 取出了1000 当前余额=" + money);
                  }
      
                  //休眠1s
                  try {
                      Thread.sleep(1000);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
          }
      }
      

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

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

相关文章

初识网络安全应急响应

初识网络安全应急响应 1.应急响应的基本能力2.应急响应的基本流程 1.应急响应的基本能力 一、数据采集、存储和检索 能对全流量数据协议进行还原&#xff1b;能对还原的数据进行存储&#xff1b;能对存储的数据快速检索。 二、事件发现 能发现高级可持续威胁&#xff08;AP…

【Redis】Redis十大数据类型—集合set

介绍 set类型是一个无序并唯一的键值集合&#xff0c;set的存储顺序不会按照插入的先后顺序进行存储。 一个集合最多可以存储2^32-1个元素。 set类型除了支持集合内的增删改查&#xff0c;同时还支持多个集合取交集、并集、差集。 Set 类型和 List 类型的区别如下&#xff1…

cgroups 实践

CPU 限制 1. 创建测试的 cgroup 在 /sys/fs/cgroup/cpu 下面创建自己的 cgroups 测试目录&#xff0c;该目录会自动创建一些文件&#xff0c;对进程或者线程的控制都可以通过修改这些文件内容自动完成。 tasks&#xff1a;被 cgroup 管理的进程 cpu.cfs_period_us&#xff1a…

多线程(九):JUC组件

在来时juc组件前&#xff0c;我们先把上一章遗漏的部分给补上。 synchronized 实现策略&#xff1a;锁升级&#xff1a; 无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁 还有一个 &#xff1a; 锁消除 锁消除即删除不必要的加锁操作。JVM在运行时&#xff0c;对一些“…

C++内联函数详解

目录 如何定义内联函数&#xff1f; 内联函数的优势 内联函数的缺点 内联函数的使用场景 示例代码 总结 在C中&#xff0c;内联函数是一种特殊的函数&#xff0c;它的作用是在程序编译时将函数的代码直接嵌入到调用该函数的代码中&#xff0c;从而避免了函数调用的开销。这…

C语言 非本地跳转实现native层TryCatch

前言 最近研究native hook的技术&#xff0c;了解到了这个非本地跳转&#xff0c;本文就是介绍他&#xff0c;对于解决native crash非常有用。 非本地跳转介绍 C语言的本地跳转是指goto、break、continue等语句&#xff0c;但是这个语句最大局限就是只能实现函数内部的跳转。…

深度学习 - 40. N-Gram 采样与 Session 数据获取 For EGES

目录 一.引言 二.订单数据预处理 1.数据样例 2.订单数据处理 3.用户 Session 构建 三.构造 sku_id 游走序列 1.获取完整 Session List 2.统计 sku_id 转移词频 3.构建 sku_id 图 4.游走构造 sku 序列 四.商品侧信息预处理 1.读取商品信息 2.Left Join 匹配侧信息 …

三甲医院体检管理系统源码PEIS ,体检总检建议、体检套餐、各种模板

PEIS体检管理系统源码 本套PEIS医院体检管理系统源码&#xff0c;采用C#语言开发&#xff0c;C/S架构&#xff0c;前台开发工具为Vs2012&#xff0c;后台数据库采用oracle大型数据库。有演示。 文末获取联系 PEIS体检管理系统适用于大中型医院的独立体检中心、干部保健处、民营…

Java基础:编译时和运行时的区别

在java开发设计过程中&#xff0c;了解java运行时和编译时的区别非常有必要。 如下从几个问题来描述两者的区别 1、如下代码片段中&#xff0c;A行和B行的区别是什么 line A是在编译时计算值&#xff0c;line B是在运行时计算值。 当该类编译后&#xff0c;如果使用一些反编译…

ROS导航

参考文章&#xff1a; (31条消息) ROS导航小车1 teb_local_planner参数(仅作记录/收集)_teb local planner参数_Crush Mome的博客-CSDN博客 运行导航&#xff1a; 1. 启动底盘控制包 &#xff1a; base_conctronl 2.启动键盘控制节点&#xff1a; rosrun teleop_twist_ke…

ROG魔霸7Plus电脑一直蓝屏错误怎么重装系统?

ROG魔霸7Plus电脑一直蓝屏错误怎么重装系统&#xff1f;有用户在使用ROG魔霸7Plus电脑的时候&#xff0c;频繁的遇到了系统蓝屏的情况。因为这样影响了自己的正常使用&#xff0c;所以想要进行系统的重新安装。那么如何进行系统重装操作呢&#xff1f;来看看以下的操作方法教学…

ONES × 中国信通院《中国企业软件研发管理白皮书》即将发布 | 预约直播

由 ONES 与中国信息通信研究院联合发起的《中国企业软件研发管理白皮书》&#xff08;下称「白皮书」&#xff09;将于 4 月 20 日 正式发布。白皮书由 ONES、中国信息通信研究院云计算与大数据研究所、招商基金管理有限公司、紫金财产保险股份有限公司、深圳市鸿合创新信息技术…

AI大模型内卷加剧,商汤凭什么卷进来

2023年&#xff0c;国内大模型何其多。 目前&#xff0c;已宣布推出或即将推出大模型的国内企业多达20余家&#xff0c;基本上能想到的相关企业都已入局。其中&#xff0c;既有资金雄厚的BAT、华为、字节等大厂&#xff0c;也有王慧文、王小川、周伯文等互联网大佬领衔的初创企…

外卖小程序01

目录 nginx反向代理和负载均衡反向代理好处nginx反向代理的配置方式 负载均衡**nginx 负载均衡的配置方式&#xff1a;****nginx 负载均衡策略&#xff1a;** 动静分离 用户密码加密需求代码实现 Swagger框架介绍使用步骤常用注解使用案例:员工登录EmployeeController实体类Emp…

科研成果 | 不同调制方式的开源数据集及其数据扩增方式

文章目录 1. 数据源2. 数据扩增2.1 基于opencv的一些基础变换2.2 基于GAN网络的方法2.2.1 SinGAN2.2.2 基于多图的GAN方法1. 数据源 网址: https://www.sigidwiki.com/wiki/VHF 每种数据基本只有一条,所以要用的话只能进行数据扩征 2. 数据扩增 两种方法: 基于opencv的一…

浏览器输入 http 自动转 https 问题解决方法

目录 表象 原因 解决方案 解决方案一 解决方案二 表象 今天在开发的过程中遇到一个问题&#xff0c;我们项目的地址是 “http://xxx.xxx.com/website/” &#xff0c;结果粘贴到浏览器里自动跳转成了 “https://xxx.xxx.com/website/”。百思不解啊&#xff0c;为啥呢。 …

git上如何通过本地仓库推送自己的代码到远程仓储

从gitHub或者gitee上拉取代码后&#xff0c;我老是想着把别人的代码保存到自己的仓库上&#xff0c;这里教你一招。 gitee的&#xff1a; 首先我们在gitee或者github上创建一个自己的仓库&#xff0c;github的我就不在展示了&#xff0c;基本上和gitee操作一样 输入相关信息…

【redis】bitmap、hyperloglog、GEO案例

【redis】bitmap、hyperloglog、GEO案例 文章目录 【redis】bitmap、hyperloglog、GEO案例前言一、面试题二、统计的类型聚合统计排序统计问题&#xff1a;思路 二值统计 0和1基数统计 三、hyperloglog1、名词理解UV 独立访客PV 页面浏览量DAU 日活跃用户MAU 月活跃度 2、看需求…

愚蠢的往事-网络安全专题之数字证书

血泪教训史&#xff0c;我被骗去办理了数字证书。 文章目录 加密算法摘要算法数字签名数字证书血泪开篇数字证书 加密算法 相关知识点&#xff1a;对称加密算法、非对称加密算法、信息完整性验证算法。 对称加密算法&#xff1a;1.加密密钥和解密密钥相同的算法&#xff0c;…

小行助学答题系统编程等级考试scratch三级真题2023年3月(含题库答题软件账号)

青少年编程等级考试scratch真题答题考试系统请点击 电子学会-全国青少年编程等级考试真题Scratch一级&#xff08;2019年3月&#xff09;在线答题_程序猿下山的博客-CSDN博客_小航答题助手 1.计算“248……128”&#xff0c;用变量n表示每项&#xff0c;根据变化规律&#xf…