JAVA中的线程、死锁、异常

线程

Thread

  • 一、程序
    • 1.一段静态代码(静态)
  • 二、进程
    • 1.动态的,有开始,有结束;
    • 2.程序的一次执行过程,
    • 3.操作系统调度分配资源的最小单位;
  • 三、线程
    • 1.进程细化为线程
    • 2.内部的一条执行路径;
    • 3.多线程,
    • 4.CPI调度、分配的最小单位;
    • 5.多线程间可以通信,一个进程共享一个堆;(会有安全问题);
    • 6.每个进程有一个独立的内存空间;
    • 7.线程调度
      • (1)分时调度;(平均分配每个时间)
      • (2)抢占式调度;(java);提高响应,设置优先级;

并行:

  • 1、多个事件,同一时间发生;
  • 2、多条指令在多个cpu上同时执行;(多核)
  • 3、三个大厨在炒菜;

并发:

  • 1、多个事件,在同一个时间段内发生;(同一时刻可能只有一个)
  • 2、Cpu快速切换处理;
  • 3、一个大厨在炒三个菜;

线程:java.lang.Thread

  • 1、创建:
    • (1)继承thread类
      • ①创建子类继承Thread,
      • ②重写run方法
      • ③创建对象
      • ④调用start方法;
        • 1)启动线程
        • 2)调用当前线程的run方法;
        • 3)结束前不能继续调start;不能让已经start的线程继续start否则报异常;
      • ⑤多个线程间的执行没有冲突,同时执行;

例1

class F extends Thread {@Overridepublic void run() {System.out.println(1);}
}

例2

class H extends Thread {static Object obj = new Object();static int total = 100;@Overridepublic void run() {/* 同步代码块 *//* 使用static修饰后可以保证obj的唯一性 */synchronized (obj) {H.total--;System.out.println(H.total);}/*此处this不能保证唯一性/慎用*/synchronized (this) {H.total--;}synchronized (Window.class) {H.total--;}synchronized (H.class) {H.total--;}}
}

例3

public class ThreadTest {@Testpublic void test(){A a = new A();a.start(); //开始创建新线程;/* 还是主线程 */for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + ": " + i);}A a2 = new A();a2.start();/* 匿名对象 */new Thread(() -> {for (int i = 0; i < 10; i++) {if(i%2==0) {System.out.println(Thread.currentThread().getName() + ": " + i);}}}).start();}
}class A extends Thread {@Overridepublic void run() {for (int i = 0; i < 10; i++) {if(i%2==0) {System.out.println(Thread.currentThread().getName() + ": " + i);}}}
}
  • (2)实现Runnable接口
    • ①创建一个实现类
    • ②实现接口内的抽象run方法
    • ③创建对象
    • ④将对象作为参数,传入Thread构造器;创建实例
    • ⑤创建实例后,调用start方法;
class J implements Runnable{int i = 100;@Overridepublic void run() {
//        synchronized (J.class){
//            method();
//        }i--;}public void method() {i--;}/* 同步方法 */public synchronized void method2() {i--;}
}
public class ThreadTest2 {public static void main(String[] args) {B b = new B();
//        new Thread(b){}.start();Thread t = new Thread(b);t.start();for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName()+ ": " + i);}Thread t2 = new Thread(b);t2.start();/* 有问题的写法? */new Thread(b){@Overridepublic void run() {for (int i = 6; i < 10; i++) {System.out.println(Thread.currentThread().getName()+ ": " + i);}}}.start();new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName()+ ": " + i);}}}).start();}
}
class B implements Runnable {@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName()+ ": " + i);}}
}
public class ThreadTest3 {public static void main(String[] args) throws InterruptedException {D d = new D();Thread t = new Thread(d);t.setName("子线程");t.setPriority(Thread.MIN_PRIORITY);t.start();Thread.currentThread().setName("主线程");for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + ": " + i);if(i == 3) {t.join();}System.out.println(Thread.currentThread().getPriority());}}
}class D implements Runnable {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + "_" + Thread.currentThread().getPriority() + ": " + i);if(i % 3 == 0) {
//                Thread.yield();}}}
}

建议:

  • 1、建议使用Runnable 方式
    • (1)避免了类的单继承性的局限性
    • (2)更适合处理有共享数据的情况

联系:

  • 1、Thread 类 本来也是实现的Runnable的方法;

常用方法:

  • 1、start
  • 2、Run:线程内主要需要的任务
  • 3、currenctThread(): 获取当前线程
  • 4、getName(): 获取线程的名称;
  • 5、SetName: 设置线程名称
  • 6、Sleep(ms): 静态方法:
    • (1)当前线程休眠指定毫秒数;
    • (2)会抛出异常;
  • 7、Yield();静态方法
    • (1)主动释放cpu的执行权
    • (2)Cpu可能去执行其他的线程;
    • (3)也可能很快继续分配回来;
  • 8、Join(); 在线程A中通过线程B调用join方法;之后线程A被阻塞,直到B执行结束;
  • 9、isAlive(); 线程是否存活
  • 10、过时方法:stop,强行结束一个线程,使其死亡。不建议使用;
  • 11、Suspend/resume; 操作失误可能造成死锁,不建议使用;
    • (1)Suspend: 暂停
    • (2)Resume:继续;

生命周期:

  • 1、Jdk1.5之前

    • (1)在这里插入图片描述
  • 2、Jdk 1.5 及之后

    • (1)在这里插入图片描述

    • (2)阻塞分的更细了

    • (3)可以查看Thread的enum枚举类State;

优先级:

  • 1、getPriority(); 获取优先级;
    • (1)默认级别都是5;
    • (2)最低的是1,最高的是10;
  • 2、THread 内部常量:
    • (1)MIN_PRIORITY: 1;
    • (2)MAX_ : 10
    • (3)NORMAL_ 5;
  • 3、setPriority(): 设置优先级;
    • (1)设置完之后不一定是哪个优先
    • (2)内部有cpu等规则;
  • 4、

线程安全

使用线程的同步机制

1、同步代码块

* (1)synchronized(同步监视器) {* ①需要被同步的代码* ②被操作的共享数据;
* };
  • ******代码块被视为一个整体,使用syncxxx包裹后,一个线程结束后。另一个线 程才能执行;
  • (2)同步监视器
  • ①俗称锁;
  • ②可以使用任何一个类的对象充当;
  • ③多个线程,必须公用同一个同步监视器;
  • ④这个对象必须是唯一的;可以尝试使用this;
  • ⑤可以使用Window.class;
  • ⑥可以使用当前类.class;
  • (3)Ctrl+alt+t

2、同步方法;

  • (1)S 如果操作共享数据的代码,在一个方法中
  • (2)直接给方法添加修饰符:synchronzied;
  • (3)非静态同步监视器默认就是this;(不可修改)
    • ①此时考虑this是否唯一;
  • (4)如果可以改成静态方法,可以考虑使用静态方法;
    • ①默认的监视器是当前类.class;
  • (5)如果this不唯一;
    • ①类声明多个实例的情况会有不唯一的情况;
  • (6)
public class WaitTest {public static void main(String[] args) {WaitTest wt = new WaitTest();wt.method();}public synchronized void method(){System.out.println(1);try {this.wait(1000);System.out.println(3);} catch (InterruptedException e) {e.printStackTrace();}this.notify();System.out.println(2);}//wait 中添加了时间之后打印顺序: 1-3-2;// wait 中不添加时间的话,只打印1;
}

推荐使用implements Runnable;方式;

5.0新特性:Lock

public class LockTest {private static final ReentrantLock lock = new ReentrantLock();public static void main(String[] args) {}public void  method() {try {lock.lock();new Thread(){@Overridepublic void run() {System.out.println(1);}}.start();} finally {lock.unlock(); //为保证unlock被执行,放到finally中;}}
}

指令重排?是什么

  • 1、volatile 修饰符避免
  • 2、Volatile A a= new A();

死锁

  • 1、互相抢占资源,等待对方释放;
  • 2、每人一个监视器,等待对方释放监视器
  • 3、拿不到监视器,对面不释放;
  • 4、见代码:DeadLockTest.java; 加上sleep后可以高概率复现死锁;
public class DeadLockTest {public static void main(String[] args) {StringBuilder s1 = new StringBuilder();StringBuilder s2 = new StringBuilder();new Thread(){@Overridepublic void run() {synchronized (s1){s1.append("a");s2.append("1");/* 加上sleep之后1秒之内不会释放,另一个线程等着用s1;这个线程等着用s2 */try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}synchronized (s2){s1.append("b");s2.append("2");}System.out.println(s1);System.out.println(s2);}}}.start();new Thread(){@Overridepublic void run() {synchronized (s2){s2.append("-3");s1.append("-c");synchronized (s1){s2.append("4");s1.append("d");}System.out.println(s1);System.out.println(s2);}}}.start();}
}

如何看待:

  • 1、避免;

原因及解决避免:(破坏死锁的形成条件)

  • 1、互斥条件:=>
    • (1)无法处理;
  • 2、占用且等待: =>
    • (1)一次性拿到所有资源;
  • 3、不可抢夺: =>
    • (1)申请不到资源时,主动释放资源;
  • 4、循环等待: =>
    • (1)改为线性顺序;排号;

Lock锁:

  • 1、解决线程安全;
  • 2、JUC:=> java.util.concurrent;
  • 3、Private static [final] ReentrantLock lock = new RenntrantLock();
  • 4、lock.lock();
    • (1)可能不安全的逻辑;
  • 5、lock.unlock(); => 必须要保证一定会执行;
  • Lock锁定对共享资源的调用;
  • Lock好过synchronized;lock不需要包上正片代码

线程通信

一、两个线程,交替打印12345678.。。

  • 1.See the code;
    • Wait();
  • 1、wait(); //进入等待并释放对同步监视器的调用;而sleep不会释放;
  • 2、Notify(); //唤醒wait;
    • (1)只能唤醒一个
    • (2)唤醒被wait中优先级最高的
    • (3)如果优先级相同,则随机唤醒;
    • (4)然后被唤醒的,继续上次被wait的地方继续执行;
  • 3、NotifyAll(): 唤醒所有wait的线程;
public class CommunicationTest {public static void main(String[] args) {Q q = new Q();Thread t1 = new Thread(q);Thread t2 = new Thread(q);t1.start();t2.start();}
}
class Q implements Runnable {static Object obj = new Object();private static int count = 100;@Overridepublic void run() {while (true) {synchronized (obj) {   // 因为和notify和wait的调用者不一致了;//                notify(); //唤起waitobj.notify(); //唤起waitif (count > 0) {try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ": " + count);count--;try {obj.wait(); //进入等待并释放对同步监视器的调用;} catch (InterruptedException e) {e.printStackTrace();}} else {break;}}}}
}
/* 实现两个线程交替打印 */
//class Q implements Runnable {
//    static Object obj = new Object();
//    private static int count = 100;
//
//    @Override
//    public void run() {
//        while (true) {
//            synchronized (this) {   //此处除了使用this,使用其他的都会报错;因为和notify和wait的调用者不一致了;
//
                notify(); //唤起wait
//                this.notify(); //唤起wait
//
//                if (count > 0) {
//                    try {
//                        Thread.sleep(10);
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }
//
//                    System.out.println(Thread.currentThread().getName() + ": " + count);
//                    count--;
//
//                    try {
//                        wait(); //进入等待并释放对同步监视器的调用;
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }
//
//                } else {
//                    break;
//                }
//            }
//
//
//        }
//    }
//}//class Q implements Runnable {
//    private  static  int count = 100;
//    @Override
//    public void run() {
//        while (count > 0) {
//            try {
//                Thread.sleep(10);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            synchronized (Q.class){
//                System.out.println(Thread.currentThread().getName() +": "+count);
//                count--;
//            }
//        }
//    }
//}

使用:

  • 1、必须用在同步代码块,或者同步方法中;(synchronized)
  • 2、不能和lock搭配使用;
  • 3、Lock需要配合condition通信(更灵活);
  • 4、监视器必须和wait和notify的调用者一致;

创建线程

  • 1、Callable: 5.0新增;
/*** @Date 2023/8/3 14:51* @Discrition  非完全代码;callable 需要结合 futureTask 来使用;*/
public class ClassableTest {public static void main(String[] args) {W w = new W();w.call();
//        try {
//            w.call();
//        } catch (Exception e) {
//            throw new RuntimeException(e);
//        }}
}class W implements Callable {@Overridepublic Object call() {synchronized (W.class) {System.out.println(1);}return null;}//    public Object call() throws Exception {
//        synchronized (W.class) {
//            System.out.println(1);
//        }
//        return null;
//    }
}
  • 2、线程池:生产中使用;

线程池:

  • 1、先创建好多个空线程,等待任务来了执行;可以复用;
public class ThreadPondTest {public static void main(String[] args) {
//        ThreadPoolExecutor executor = new ThreadPoolExecutor();}
}class R {}

异常

Throwable两个子类:

1、Error

  • (1)处理方式:只能改代码;(jvm资源耗尽,无法处理)
  • (2)错误类型:
    • ①Stack Overflow Error;栈溢出
    • ②OutOfMemoryError;堆内存移除;==>OOM

2、Exception

  • (1)可以处理,通过代码catch让程序继续执行;
  • (2)区分:
    • ①Java~运行时异常:只有一个(runtimeException=>扩展开还有很多)
    • ②Javac~编译时异常

Exception:

  • 1、将无线重复的ifelse=》改为。。。
  • 2、将所有可能报错的放在一起处理下;
public class ThrowsTest {@Testpublic void test(){try {ThrowsTest.method1();}finally {System.out.println(1);}System.out.println(2);}public static void method1() throws OutOfMemoryError{int[] arr = new int[] {1,2};System.out.println(arr[2]);System.out.println(3);}@Testpublic void test2(){new B();}
}
class A {void method1() throws NullPointerException{}
}
class B extends A{void method1(){}
}

处理方式:

方式一 try-catch-finally(抓抛模型)**

1、自定义逻辑

  • (1)抛出: 产生异常对象,抛出;
  • (2)抓:捕获并处理,处理后代码可以继续执行;
  • (3)Finally 无论什么情况,代码块内都会执行;

2、printStackTrace (最常用-推荐)打印堆栈信息

  • (1)1111
  • 3、
  • 4、
  • 5、
  • 6、 运行时异常不做处理,主要处理编译时异常;

Catch结构顺序:

  • 1、如果有多个catch结构,其中的异常类型无子父类关系则无顺序
  • 2、如果有子父类关系,则父类要放到后面;

Finally:

  • 1、在catch还存在异常的话,后面的代码不放到finally中的话不会被执行;
  • 2、一定要被执行的语句,放到finally中;
  • 3、Finally比catch先执行;
  • 4、Finally比try中先执行;

System.exit(0); 虚拟机强行结束;

方式二

  • 1、Throws
  • 2、格式:
    • (1)Throws 类型1, 类型2 。。。 ;
    • (2)Public void test() throws NullxxxxException{}
  • 3、是否解决了异常
    • (1)向上抛出,不算真正解决;需要调用者来继续处理;

继承:

  • 1、父类方法使用了throws,子类的方法如果也使用throws则必须为同类型异常,或子类异常,可以不是用throws;
  • 2、RuntimeException 这个范围类型写了没用;
  • 3、如果父类的方法没有抛出异常,则子类方法中不能抛出异常;

手动抛出异常:throw;

  • 1、throw new Object(“description”);
public class ThrowsTest {@Testpublic void test(){try {ThrowsTest.method1();}finally {System.out.println(1);}System.out.println(2);}public static void method1() throws OutOfMemoryError{int[] arr = new int[] {1,2};System.out.println(arr[2]);System.out.println(3);}@Testpublic void test2(){new B();}
}
class A {void method1() throws NullPointerException{}
}
class B extends A{void method1(){}
}

自定义异常

  • 1、创建类继承自某个异常类;
  • 2、通常继承自 RuntimeException 或者Exception;
public class DIYException extends RuntimeException{
}
  • 3、空参构造器
  • 4、形参构造器
  • 5、常量(序列版本号);
  • 6、,即可抛出
public class ManuThrowTest {int i = 1;@Testpublic void test(){this.i = 0;this.method1();}public void method1(){if(this.i > 0) {}else {throw new  NullPointerException("ghjg");}}public void method2() throws Exception {throw new Exception("123"); //必须搭配处理;(因为是编译时错误)}public void method3() {throw new DIYException(); //自定义异常类;}
}

为什么要自定义?

  • 1、见名知意;
  • 2、已有类型不足以见名知意;

~~~~运行时异常可以不处理,编译时异常必须要处理;或trycatch或throws~~~~

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

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

相关文章

TCN-BiGRU-Attention(12种算法优化TCN-BiGRU-Attention)(多输入单输出)

12种算法优化TCN-BiGRU-Attention模型预测的代码。其中Attention模型可以改为单头或者多头&#xff0c;在代码中就是改个数字而已。代码注释已写好如何更改。 TCN-BiGRU-Attention&#xff08;12种算法优化TCN-BiGRU-Attention&#xff09;&#xff08;多输入单输出)代码获取戳…

【C++】C++11--- 类的新功能

目录 类的新功能 默认成员函数 示例 类成员变量初始化 强制生成默认函数的关键字default 禁止生成默认函数的关键字delete 类的新功能 默认成员函数 构造函数析构函数拷贝构造函数拷贝赋值重载取地址重载const取地址重载 C11在原先的6个默认成员函数的基础上&#xff0c…

WebDriver使用带用户名密码验证的IP代理解决方案

背景&#xff0c;使用python3 selenium 先定义一个方法&#xff0c;这里主要用到了chrome插件的功能&#xff0c;利用这个插件来放进代理内容。 def create_proxy_auth_extension(proxy_host, proxy_port,proxy_username, proxy_password, schemehttp):manifest_json "…

【Java基础】Maven继承

1. 前言 Maven 在设计时&#xff0c;借鉴了 Java 面向对象中的继承思想&#xff0c;提出了 POM 继承思想。 2. Maven继承 当一个项目包含多个模块时&#xff0c;可以在该项目中再创建一个父模块&#xff0c;并在其 POM 中声明依赖&#xff0c;其他模块的 POM 可通过继承父模…

基于TF的简易关键字语音识别

⚠申明&#xff1a; 未经许可&#xff0c;禁止以任何形式转载&#xff0c;若要引用&#xff0c;请标注链接地址。 全文共计10182字&#xff0c;阅读大概需要10分钟 &#x1f308;更多学习内容&#xff0c; 欢迎&#x1f44f;关注&#x1f440;【文末】我的个人微信公众号&#…

word文件名和创建时间可以同时提取出来吗?答案是肯定的!方法很简单 一键就搞定

在日常生活和工作中&#xff0c;我们经常需要处理大量的Word文件&#xff0c;有时候需要提取这些文件的文件名以及它们的创建时间。虽然这听起来可能是一个复杂的任务&#xff0c;但实际上&#xff0c;通过一些简单的方法和工具&#xff0c;我们可以轻松地完成这一任务。在本文…

「C++ 内存管理篇 04」动态二维数组

目录 一. 使用calloc/free开辟和释放二维数组 二、 使用new/delete开辟和释放二维数组 一. 使用calloc/free开辟和释放二维数组 让一个二级指针变量存放动态开辟的一级指针数组的起始地址&#xff0c;然后让这些一级指针指向动态开辟的基本类型的数组&#xff1a; // 开辟一个大…

机器学习项目实践-基础知识部分

环境建立 我们做项目第一步就是单独创建一个python环境&#xff0c;Python新的隔离环境 创建&#xff1a;python -m venv ml 使用&#xff1a;.\Scripts\activate python -m venv ml 是在创建一个名为 ml 的虚拟环境&#xff0c;这样系统会自动创建一个文件夹ml&#xff0c;…

YOLOv5改进(一)MobileNetv3替换主干网络

前言 本篇博客主要讲解YOLOv5主干网络的替换&#xff0c;使用MobileNetv3实现模型轻量化&#xff0c;平衡速度和精度。以下为改进的具体流程~ 目录 一、改进MobileNetV3_Small 第一步&#xff1a;修改common.py,新增MobileNetV3 第二步&#xff1a;在yolo.py的parse_model函…

算法提高之玉米田

算法提高之玉米田 核心思想&#xff1a;状态压缩dp 将图存入g数组 存的时候01交换一下方便后面判断即g数组中0为可以放的地方 state中1为放的地方 这样只要state为1 g为0就可以判断不合法 #include <iostream>#include <cstring>#include <algorithm>#includ…

linux 内核编译

目录 Linux操作系统框架 Linux内核的主要功能&#xff1a; Linux的内核目录结构&#xff1a; 结构图: 详细介绍&#xff1a; uname - a 补充 编译之前 UTC 时间补充 Linux内核编译流程: 方法一: 官方内核编译: 1. 运行 build.sh 脚本&#xff0c; 记得加 sudo 权…

【RAG 论文】GenRead:“generate-read“ 可能比 “retrieve-read“ 更有效

论文&#xff1a;Generate rather than Retrieve: Large Language Models are Strong Context Generators ⭐⭐⭐⭐ ICLR 2023 Code: github.com/wyu97/GenRead 一、论文速读 该工作发现&#xff1a;由 LLM 生成的文档中&#xff0c;往往比 retrieved documents 更可能包含正确…