多线程——学习记录2

目录

        • 单例模式
          • 两种单例写法
          • 饿汉式和懒汉式的区别
        • Runtime
        • Timer 计时器
        • 两个线程间的通信
          • 关键点:wait()线程等待 和 notify()随机唤醒等待的线程;
        • 三个或三个以上间的线程通信
          • 关键点:notifyAll()唤醒所有线程
        • 线程间通信需要注意的问题
        • JDK1.5的新特性互斥锁
        • 线程组的概述和使用
        • 线程的五种状态
        • 线程池的概述和使用

单例模式

  • 单例设计模式:保证类在内存中只有一个对象。

  • 如何保证类在内存中只有一个对象呢?

    • (1)控制类的创建,不让其他类来创建本类的对象。private
    • (2)在本类中定义一个本类的对象。Singleton s;
    • (3)提供公共的访问方式。 public static Singleton getInstance(){return s}
两种单例写法
  • 第一种单例写法
    • 饿汉式
//饿汉式
class Singleton {//1、私有构造函数private Singleton() {}//2、创建本类对象private static Singleton singleton = new Singleton();//3、对外提供公共的访问方法public static Singleton getInstance() {             //获取实例return singleton;}
}
  • 第二种单例写法
    • 懒汉式
//懒汉式
class Singleton1 {//1、私有构造函数private Singleton1() {}//2、声明一个本类的引用private static Singleton1 singleton1;//3、对外提供公共的访问方法public static Singleton1 getInstance() {         //获取实例if (singleton1 == null) {singleton1 = new Singleton1();}return singleton1;}
}
饿汉式和懒汉式的区别
  • 1、饿汉式是空间交换时间,懒汉式是时间交换空间
  • 2、在多线程访问时,饿汉式不会创建多个对象,而懒汉式有可能会创建多个对象

Runtime

  • Runtime类是一个单例类,可以获取运行时对象
  public static void main(String[] args) throws IOException {Runtime runtime = Runtime.getRuntime();     //获取运行时对象//exec在单独的进程中执行指定的字符串命令//runtime.exec("shutdown -s -t 300");       //300秒后关机runtime.exec("shutdown -a");      //取消关机}

在这里插入图片描述

Timer 计时器

线程用其安排以后在后台线程中执行的任务,可安排任务执行一次或者定期重复执行

 public static void main(String[] args) throws IOException, InterruptedException {Timer timer = new Timer();//在指定时间安排指定任务//第一个参数,是安排的任务,第二个参数是执行的时间(执行时间需要当前年份减去1900,月份范围0-11),第三个参数是重复执行的间隔时间timer.schedule(new MyTimerTask(),new Date(123,7,22,13,49,30));while (true){Thread.sleep(1000);System.out.println(new Date());}
}class MyTimerTask extends TimerTask {@Overridepublic void run() {System.out.println("起床");}
}

在这里插入图片描述

 public static void main(String[] args) throws IOException, InterruptedException {Timer timer = new Timer();//在指定时间安排指定任务//第一个参数,是安排的任务,第二个参数是执行的时间(执行时间需要当前年份减去1900,月份范围0-11),第三个参数是重复执行的间隔时间//下面是到了指定时间后每5秒执行一次timer.schedule(new MyTimerTask(),new Date(123,7,22,13,49,30),5000);while (true){Thread.sleep(1000);System.out.println(new Date());}}class MyTimerTask extends TimerTask {@Overridepublic void run() {System.out.println("起床");}
}

在这里插入图片描述

两个线程间的通信

关键点:wait()线程等待 和 notify()随机唤醒等待的线程;
  • 1、什么时候需要通信
    • 多个线程并发执行时, 在默认情况下CPU是随机切换线程的
    • 如果我们希望他们有规律的执行, 就可以使用通信, 例如每个线程执行一次打印
  • 2、怎么通信
    • 如果希望线程等待, 就调用wait()
    • 如果希望唤醒等待的线程, 就调用notify();
    • 这两个方法必须在同步代码中执行, 并且使用同步锁对象来调用
  public static void main(String[] agr) {final printer p = new printer();new Thread() {public void run() {while (true) {try {p.print1();} catch (InterruptedException e) {e.printStackTrace();}}}}.start();new Thread() {public void run() {while (true) {try {p.print2();} catch (InterruptedException e) {e.printStackTrace();}}}}.start();}/*** 非静态的同步方法的锁对象是this* 静态的同步方法的锁对象是该类的字节码对象*/
class printer {private int flag = 1 ;public void print1() throws InterruptedException {synchronized (this) {if (flag != 1){this.wait();                            //当前线程等待}System.out.print("恩");System.out.print("施");System.out.print("大");System.out.print("峡");System.out.print("谷");System.out.print("\r\n");flag = 2;this.notify();                                //随机唤醒单个等待的线程}}/** 非静态同步函数的锁是:this* 静态的同步函数的锁是:字节码对象*/public void print2() throws InterruptedException {synchronized (this) {if (flag != 2){this.wait();                            //当前线程等待}System.out.print("屏");System.out.print("山");System.out.print("景");System.out.print("区");System.out.print("\r\n");flag = 1 ; //改变flag的值,让当前线程等待,唤醒其他等待的线程this.notify();                              //随机唤醒单个等待的线程}}
}

在这里插入图片描述

三个或三个以上间的线程通信

关键点:notifyAll()唤醒所有线程
  • 多个线程通信的问题
    • notify()方法是随机唤醒一个线程
    • notifyAll()方法是唤醒所有线程
    • JDK5之前无法唤醒指定的一个线程
    • 如果多个线程之间通信, 需要使用notifyAll()通知所有线程, 用while来反复判断条件
public class Synchronized {public static void main(String[] agr) {final printer p = new printer();new Thread() {public void run() {while (true) {try {p.print1();} catch (InterruptedException e) {e.printStackTrace();}}}}.start();new Thread() {public void run() {while (true) {try {p.print2();} catch (InterruptedException e) {e.printStackTrace();}}}}.start();new Thread() {public void run() {while (true) {try {p.print2();} catch (InterruptedException e) {e.printStackTrace();}}}}.start();new Thread() {public void run() {while (true) {try {p.print3();} catch (InterruptedException e) {e.printStackTrace();}}}}.start();}
}/*** 非静态的同步方法的锁对象是this* 静态的同步方法的锁对象是该类的字节码对象*/
class printer {private int flag = 1 ;public void print1() throws InterruptedException {synchronized (this) {while (flag != 1){this.wait();                            //当前线程等待}System.out.print("恩");System.out.print("施");System.out.print("大");System.out.print("峡");System.out.print("谷");System.out.print("\r\n");flag = 2;this.notifyAll();                              //随机唤醒单个等待的线程}}/** 非静态同步函数的锁是:this* 静态的同步函数的锁是:字节码对象*/public void print2() throws InterruptedException {synchronized (this) {while (flag != 2){this.wait();                            //当前线程等待}System.out.print("屏");System.out.print("山");System.out.print("景");System.out.print("区");System.out.print("\r\n");flag = 3 ; //改变flag的值,让当前线程等待,唤醒其他等待的线程this.notifyAll();                              //随机唤醒单个等待的线程}}public void print3() throws InterruptedException {synchronized (this) {while (flag != 3){                          //while循环是循环判断,每次都会判断标记this.wait();                            //当前线程等待}System.out.print("A");System.out.print("B");System.out.print("C");System.out.print("D");System.out.print("E");System.out.print("F");System.out.print("\r\n");flag = 1 ; //改变flag的值,让当前线程等待,唤醒其他等待的线程this.notifyAll();                             //随机唤醒单个等待的线程}}
}

在这里插入图片描述

线程间通信需要注意的问题

  1. 在同步代码块中,用哪个对象锁,就用哪个对象调用wait方法
  2. 为什么wait方法和notify方法定义在object这个类中?
    因为锁对象可以是任意对象,object是所有类的基类,所以wait方法和notify方法定义在object这个类中
  3. sleep方法和wait方法的区别
  • sleep方法必须传入参数,参数就是时间,时间到了自动醒来
    wait方法可以传入参数也可以不传入参数,传入参数就是在参数的时间结束后等待,不传入时间就是直接等待
  • sleep方法在同步函数或同步代码块中,不释放锁
    wait方法在同步函数或者同步代码块中,释放锁

JDK1.5的新特性互斥锁

  • 1.同步
    • 使用ReentrantLock类的lock()和unlock()方法进行同步
  • 2.通信
    • 使用ReentrantLock类的newCondition()方法可以获取Condition对象
    • 需要等待的时候使用Condition的await()方法, 唤醒的时候用signal()方法
    • 不同的线程使用不同的Condition, 这样就能区分唤醒的时候找哪个线程了
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;public class Synchronized {public static void main(String[] agr) {final printer p = new printer();new Thread() {public void run() {while (true) {try {p.print1();} catch (InterruptedException e) {e.printStackTrace();}}}}.start();new Thread() {public void run() {while (true) {try {p.print2();} catch (InterruptedException e) {e.printStackTrace();}}}}.start();new Thread() {public void run() {while (true) {try {p.print3();} catch (InterruptedException e) {e.printStackTrace();}}}}.start();new Thread() {public void run() {while (true) {try {p.print3();} catch (InterruptedException e) {e.printStackTrace();}}}}.start();}
}/*** 非静态的同步方法的锁对象是this* 静态的同步方法的锁对象是该类的字节码对象*/
class printer {private ReentrantLock r = new ReentrantLock();private Condition c1 = r.newCondition();private Condition c2 = r.newCondition();private Condition c3 = r.newCondition();private int flag = 1;public void print1() throws InterruptedException {r.lock();                                        //获取锁if (flag != 1) {c1.await();                            //当前线程等待}System.out.print("恩");System.out.print("施");System.out.print("大");System.out.print("峡");System.out.print("谷");System.out.print("\r\n");flag = 2;c2.signal();r.unlock();}/** 非静态同步函数的锁是:this* 静态的同步函数的锁是:字节码对象*/public void print2() throws InterruptedException {r.lock();if (flag != 2) {c2.await();                            //当前线程等待}System.out.print("屏");System.out.print("山");System.out.print("景");System.out.print("区");System.out.print("\r\n");flag = 3; //改变flag的值,让当前线程等待,唤醒其他等待的线程c3.signal();r.unlock();}public void print3() throws InterruptedException {r.lock();if (flag != 3) {                         c3.await();                            //当前线程等待}System.out.print("A");System.out.print("B");System.out.print("C");System.out.print("D");System.out.print("E");System.out.print("F");System.out.print("\r\n");flag = 1; //改变flag的值,让当前线程等待,唤醒其他等待的线程c1.signal();r.unlock();}
}

在这里插入图片描述

线程组的概述和使用

A:线程组概述

  • Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。
  • 默认情况下,所有的线程都属于主线程组。
    • public final ThreadGroup getThreadGroup()//通过线程对象获取他所属于的组
    • public final String getName()//通过线程组对象获取他组的名字
  • 给线程设置分组
    • 1,ThreadGroup(String name) 创建线程组对象并给其赋值名字
    • 2,创建线程对象
    • 3,Thread(ThreadGroup?group, Runnable?target, String?name)
    • 4,设置整组的优先级或者守护线程
public class ThreadGroup {public static void main(String[] agr) {//demo1();java.lang.ThreadGroup tg = new java.lang.ThreadGroup("我是一个新的线程组");          //创建新的线程组MyRunnable myRunnable = new MyRunnable();                                               //创建Runnable的子类对象Thread t1 = new Thread(tg,myRunnable,"张三");                                      //将线程t1放在组中Thread t2 = new Thread(tg,myRunnable,"李四");                                      //将线程t2放在组中System.out.println(t1.getThreadGroup().getName());                                      //获取名字System.out.println(t2.getThreadGroup().getName());//通过组名称设置后台线程,表示改组的线程都是后台线程tg.setDaemon(true);}private static void demo1() {MyRunnable myRunnable = new MyRunnable();Thread t1 = new Thread(myRunnable, "线程1");Thread t2 = new Thread(myRunnable, "线程2");java.lang.ThreadGroup tg1 = t1.getThreadGroup();java.lang.ThreadGroup tg2 = t2.getThreadGroup();System.out.println(tg1.getName());              //默认是主程序System.out.println(tg2.getName());}
}class MyRunnable implements Runnable {@Overridepublic void run() {for (int i = 0; i < 1000; i++) {System.out.println(Thread.currentThread().getName() + "....." + i);}}
}

在这里插入图片描述

线程的五种状态

在这里插入图片描述

线程池的概述和使用

  • :线程池概述
    • 程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池
  • B:内置线程池的使用概述
    • JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
      • public static ExecutorService newFixedThreadPool(int nThreads)
      • public static ExecutorService newSingleThreadExecutor()
      • 这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法
      • Future<?> submit(Runnable task)
      • Future submit(Callable task)
    • 使用步骤:
      • 创建线程池对象
      • 创建Runnable实例
      • 提交Runnable实例
      • 关闭线程池
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class Demo5_Executors {public static void main(String[] agr) {ExecutorService pool = Executors.newFixedThreadPool(2);  //创建线程池pool.submit(new MyRunnable());                                    //将线程放进线程池并执行pool.submit(new MyRunnable());pool.shutdown();                                                  //关闭线程池}
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue vs react vue3 和 react区别

vue 简介&#xff1a;渐进式 JavaScript 框架 来源&#xff1a;最初由 Evan You &#xff08;尤雨溪&#xff09;于2014年开发。Evan You之前在Google研究过AngularJS&#xff0c;并提取了Angular的部分特性以提供一个更轻量级的框架 版本&#xff1a; vue 1x&#xff1a;2014…

面试热题(复原ip地址)

有效 IP 地址 正好由四个整数&#xff08;每个整数位于 0 到 255 之间组成&#xff0c;且不能含有前导 0&#xff09;&#xff0c;整数之间用 . 分隔。 例如&#xff1a;"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址&#xff0c;但是 "0.011.255.24…

SpringBoot 01 如何创建 和pom的解析

目录 1 Springboot的创建 步骤 2 项目的书写和运行 创建service包并在其下写一个service文件 项目的运行 pom文件的一些配置 parent web test 打包 打包过程 1 Springboot的创建 步骤 首先new一个新项目 然后依照如下创建 2 项目的书写和运行 创建service包并…

MySQL MVCC的详解之Read View

文章目录 概要一、基于UNDO LOG的版本链1.1、行记录结构1.2、了解UNDO LOG1.3、版本链 二、Read View2.1、判定机制 三、参考 概要 在上文中&#xff0c;我们提到了MVCC&#xff08;Multi-Version Concurrency Control)多版本并发控制&#xff0c;是通过undo log来实现的。那具…

低代码系列——初步认识低代码

低代码系列目录 一、初步认识低代码 二、低代码是什么 三、低代码平台的概念和分类 01.无代码开发平台 02.低代码应用平台(LCAP) 03.多重体验开发平台(MXDP) 04.智能业务流程管理套件(iBPMS) 四、低代码的能力指标 五、低代码平台jnpf 表单 报表 流程 权限 一、初步认识低代码 …

隧道HTTP具备的条件

作为一名专业的爬虫代理供应商&#xff0c;我们都知道使用代理是保证爬虫的高效性和稳定性的重要手段之一。而隧道代理则是近年来备受推崇的一种代理形式&#xff0c;它通过将请求通过隧道传输&#xff0c;可以有效地隐藏爬虫的真实IP地址&#xff0c;提高爬虫的反爬能力。 在…

Maven 一键部署到 SSH 服务器

简介 利用 Maven Mojo 功能一键部署 jar 包或 war 包到远程服务器上。 配置 在 maven 的setting.xml 配置服务器 SSH 账号密码。虽然可以在工程的 pom.xml 直接配置&#xff0c;但那样不太安全。 <servers><server><id>iq</id><configuration&…

完全免费的GPT,最新整理,2023年8月24日,已人工验证,不用注册,不用登录,更不用魔法,点开就能用

完全免费的ChatGPT&#xff0c;最新整理&#xff0c;2023年8月24日&#xff0c;已人工验证&#xff0c; 不用注册&#xff0c;不用登录&#xff0c;更不用魔法&#xff0c;点开就能用&#xff01; 第一个&#xff1a;网址地址统一放在文末啦&#xff01;文末直达 看上图你就能…

无涯教程-PHP - Session选项

从PHP7 起&#xff0c; session_start()()函数接受一系列选项&#xff0c;以覆盖在 php.ini 中设置的会话配置指令。这些选项支持 session.lazy_write &#xff0c;默认情况下此函数为on&#xff0c;如果会话数据已更改&#xff0c;则会导致PHP覆盖任何会话文件。 添加的另一个…

[JavaWeb]【八】web后端开发-Mybatis

目录 一 介绍 二 Mybatis的入门 2.1 快速入门 2.1.1 准备SpringBoot工程 2.1.2 创建数据库mybatis以及对应库表user 2.1.3 创建User实体类 2.1.4 配置application.properties数据库连接信息 2.1.5 编写sql语句&#xff08;注解方式&#xff09; 2.1.6 测试运行 2.1.7 配…

通过浏览器控制台使用js脚本进行浏览器操作(定时点击等)

进行此操作前我们首先需要了解js编程语言 --了解之后我们就可以去操作了 这里我们拿csdn评论举例子&#xff1b; 点开评论界面右键审查元素 此时我们需要找到输入框dom和评论按钮dom 点击元素之后点击箭头然后去界面上选中文本框核按钮 然后我们就可以知道这个文本框的id 同…

POI groupRow 折叠分组,折叠部分不显示问题

折叠组是什么&#xff1f;如图就是用POI 实现的&#xff0c;代码很简单&#xff1a;sheet.groupRow(开始行&#xff0c;结束行)即可 但是万万没想到&#xff0c;最终实现出的结果&#xff0c;合并的组&#xff0c;有一部分并没有渲染出来&#xff0c;如下图&#xff1a; 因为我…

分布式下的session共享问题

首页我们确定在分布式的情况下session是不能共享的。 1.不同的服务&#xff0c;session不能共享&#xff0c;也就是微服务的情况下 2.同一服务在分布式情况&#xff0c;session同样不能共享&#xff0c;也会是分布式情况 分布式下session共享问题解决方案(域名相同) 1.session复…

【leetcode 力扣刷题】交换链表中的节点

24. 两两交换链表中的节点 24. 两两交换链表中的节点两两节点分组&#xff0c;反转两个节点连接递归求解 24. 两两交换链表中的节点 题目链接&#xff1a;24. 两两交换链表中的节点 题目内容&#xff1a; 题目中强调不能修改节点内部值&#xff0c;是因为如果不加这个限制的话…

java.lang.IllegalStateException: Failed to load ApplicationContext异常

错误原由 今天在编写SpringBoot项目整合MyBatis框架的过程中&#xff0c;产生了这个错误 java.lang.IllegalStateException: Failed to load ApplicationContextat org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheA…

Linux和其他类Unix系统的GNU coreutils 知多少

GNU coreutils是GNU项目的一部分&#xff0c;它是一组基本的命令行工具集&#xff0c;用于操作和管理Linux和其他类Unix系统中的文件和数据流。这些工具被广泛用于终端和脚本中&#xff0c;提供了许多常用的功能和实用程序。Linux和其他类Unix系统的GNU coreutils 知多少&#…

用 VB.net,VBA 两种方式 读取单元格内的 换行数据,并出力到 CSV文件

用 VB.net&#xff0c;VBA 两种方式 读取单元格内的 换行数据&#xff0c;并出力到 CSV文件 需求 如下图所示&#xff0c;为了生成csv文件导入数据库&#xff0c;需要将下图 的 1 和 2 拼接成 如下 3 所示的一行数据&#xff0c; 开头为 1 &#xff0c;往后为 2 的换行数据 将换…

HTML中SCRIPT 标签中的那些属性

在HTML中&#xff0c; <script> 标签用于嵌入或引用JavaScript代码。 在 <script> 标签中&#xff0c;有两个属性可以用来控制脚本的加载和执行方式&#xff1a; async 和 defer 。 当然这也是常见的一道面试题&#xff0c; async 和 defer 的作用和区别。 asy…

[Go版]算法通关村第十三关黄金——数字数学问题之数论问题(最大公约数、素数、埃氏筛、丑数)

目录 题目&#xff1a;辗转相除法&#xff08;求最大公约数&#xff09;思路分析&#xff1a;辗转相除法&#xff08;也叫欧几里得算法&#xff09;gcd(a,b) gcd(b,a mod b)复杂度&#xff1a;时间复杂度 O ( n l o g ( m a x ) ) O(nlog(max)) O(nlog(max))、空间复杂度 O (…

轻松实现文件夹名互换,快速批量改名高手工具助您高效管理!

亲爱的用户们&#xff0c;您是否曾经需要将文件夹的名称进行互换&#xff0c;但手动一个一个改名太过繁琐&#xff1f;现在&#xff0c;我们为您推出一款高效的文件夹批量改名工具&#xff0c;让您轻松实现文件夹名的互换&#xff0c;帮助您更好地管理文件&#xff01; 首先&a…