面试题:说说Java并发运行中的一些安全问题

news2024/12/23 5:13:23

文章目录

  • 1.什么是多线程并发运行安全问题?
  • 2.用synchronized修饰的方法
  • 3.同步块
  • 4.使用Synchronized修饰静态方法
  • 5.互斥锁
  • 6.死锁现象
  • 7.wait()和sleep()的区别


1.什么是多线程并发运行安全问题?

当多个线程并发操作一个数据时,由于线程操作的时间不可控的原因,可能会导致操作该数据时的过程没有按照程序设计的执行顺序运行,导致操作后数据出现混乱,严重时可导致系统瘫痪。

2.用synchronized修饰的方法

当一个方法用synchronized修饰,那么该方法变为“同步方法“多个线程不能同时进入方法内容运行的,必须时有顺序的一个一个运行,这样就能避免并发安全问题。

案例:抢豆豆事件(使豆豆的剩余量不能为负数)

public class SyncDemo {
 public static void main(String[] args) {
  Table table=new Table();
  Thread t1=new Thread(){
   public void run(){
    while(true){
     int n=table.getBean();
     Thread.yield();
     System.out.println(Thread.currentThread().getName()+",豆豆还剩"+n);
    }
   }
  };
  
  Thread t2=new Thread(){
   public void run(){
    while(true){
     int n=table.getBean();
     Thread.yield();
     System.out.println(Thread.currentThread().getName()+",豆豆还剩"+n);
    }
   }
  };
  
  t1.start();
  t2.start();
 }
}


class Table{
 private  int bean=10;
 public synchronized int getBean(){
  if(bean==0){
   throw new RuntimeException("没有豆豆了");
  }
  /*
   * yield()将导致线程从运行状态转到就绪状态,但是可能没有效果
   * 作用时暂停当前正在执行的线程对象(放弃当前拥有的cpu资源),
   * 并执行其他线程。
   */
  Thread .yield();//模拟切换线程
  return bean--;
 }
}

运行结果:

当豆豆剩余量为0时,程序抛出异常。如果不加锁的话,程序有一定的几率会跳过豆豆为0,这个条件,而一直运行下去。

3.同步块

  1. 有效的缩小同步范围可以在保证并发安全的前提下尽可能的提高效率。

  2. 同步块

synchronized(同步监视器){
  //需要同步运行的代码片段
}
  1. 同步块可以更灵活准确的锁定需要同步运行的代码片段,这样可以有效缩小同步范围提高并发效率,但是需要注意,必须保证多个线程看到同步监视器对象是同一个对象才可以。

案例:模拟商场买衣服

public class Syncdemo2 {
 public static void main(String[] args) {
  Shop shop=new Shop();
  Thread t1=new Thread(){
   public void run(){
    shop.buy();
   }
  };
  
  
  Thread t2=new Thread(){
   public void run(){
    shop.buy();
   }
  };
  
  t1.start();
  t2.start();
 }
}


class Shop{
 public void buy(){
  try {
   String name=Thread.currentThread().getName();
   System.out.println(name+"选衣服");
   Thread.sleep(2000);
   synchronized (this) {
    System.out.println(name+"试衣服");
    Thread.sleep(2000);
   }
   System.out.println(name+"结账走人");
  } catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
    
 }
}

运行结果:

Thread-1选衣服
Thread-0选衣服
Thread-1试衣服
Thread-1结账走人
Thread-0试衣服
Thread-0结账走人

分析:

两个线程不会同时在试衣服,因为在试衣服环节设置了同步块,这使线程在运行试衣服环节时变得有序。

4.使用Synchronized修饰静态方法

  1. 静态方法若使用了Synchronized修饰后,那么方法一定具有同步效果

  2. 静态方法的对象是当前类的对象

  3. class类的每一个实例用于表达jvm加载一个类,当jvm加载一个类时后就会实例化一个class的实例用于表示它,每一个类在jvm都有且只有一个class的实例,所以静态方法锁的就是当前类对应的class的实例。

public class Syncdemo3 {
 public static void main(String[] args) {
  Thread t1=new Thread(){
   public void run(){
    Foo.dosome();
   }
  };
  
  
  Thread t2=new Thread(){
   public void run(){
    Foo.dosome();
   }
  };
  
  t1.start();
  t2.start();
 }
}


class Foo{
 public synchronized static void dosome(){
  try {
   String name=Thread.currentThread().getName();
   System.out.println(name+"正在运行dosome方法");
   Thread.sleep(3000);
   System.out.println(name+"运行结束》》");
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}

5.互斥锁

使用synchronized锁定多段代码,而锁的对象相同时,这些代码片段之间就是互斥锁,多个线程不能同时执行这些方法。

public class Syncdemo4 {
 public static void main(String[] args){
  Eoo eoo=new Eoo();
  Thread t1=new Thread(){
   public void run(){
    eoo.test01();
   }
  };
  
  Thread t2=new Thread(){
   public void run(){
    eoo.test02();
   }
  };
  t1.start();
  t2.start();
 }
}


class Eoo{
 public synchronized void test01(){
  String name=Thread.currentThread().getName();
  System.out.println(name+"正在运行1方法");
  try {
   Thread.sleep(3000);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  System.out.println(name+"1运行完毕");
 }
 
 public synchronized void test02(){
  String name=Thread.currentThread().getName();
  System.out.println(name+"正在运行2方法");
  try {
   Thread.sleep(3000);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  System.out.println(name+"2运行完毕");
  
 }
}

运行结果:

Thread-0正在运行1方法
Thread-01运行完毕
Thread-1正在运行2方法
Thread-12运行完毕

结果分析:

因为两个线程锁的对象相同,因此,当一个线程运行它的方法时,另一个线程不会一起运行运行它的方法,直到,一个线程运行结束后,他才可以进入这个类,来运行他的方法。

6.死锁现象

线程都是保持着自己的锁,但是都是等待对方来释放锁,就出现互相”僵持“的情况,导致程序不会继续向后运行。

public class Syncdemo5 {
 public static void main(String[] args) {
  Poo p=new Poo();
  Thread t1=new Thread(){
   public void run(){
    p.method1();
   }
  };
  
  Thread t2=new Thread(){
   public void run(){
    p.method2();
   }
  };
  t1.start();
  t2.start();
 }
}


class Poo{
 Object A=new Object();
 Object B=new Object();
 
 public void method1(){
  String name=Thread.currentThread().getName();
  synchronized (A) {
   try {
    System.out.println(name+"A正在运行。。。");
    Thread.sleep(3000);
    System.out.println(name+"A运行完毕");
    method2();
   } catch (Exception e) {
    e.printStackTrace();
   }
  }
 }
 
 
 public void method2(){
  String name=Thread.currentThread().getName();
  synchronized (B) {
   try {
    System.out.println(name+"B正在运行。。。");
    Thread.sleep(3000);
    System.out.println(name+"B运行完毕");
    method1();
   } catch (Exception e) {
    e.printStackTrace();
   }
  }
 }
}

运行结果:

Thread-0A正在运行。。。
Thread-1B正在运行。。。
Thread-0A运行完毕
Thread-1B运行完毕

结果分析:

虽然有输出结果,但是,程序并没有运行结束,两个线程都等待着对方来释放锁,而僵持不下。

7.wait()和sleep()的区别

  1. wait是object类中的方法,sleep是Thread中的方法

  2. 最主要的是sleep方法调用后,并没有释放锁,使得线程仍然可以同步控制,sleep不会让出出系统资源,sleep方法可以在任何地方使用,而wait必须在synchronized方法或者synchronized 块中使用,否则会抛出异常(java.lang.IllegalMonitorStateException),wait方法不仅让出cpu,还会释放已占有的同步资源;

  3. sleep必须捕获异常,而wait,nofify和nofifyAll不需要捕获异常。

  4. sleep是让某个线程暂时运行一段时间,其控制范围是由当前线程决定的,主动权在自己手里,而wait是由某个确定的对象来调用,主动权在某个对象手里。

public class WaitDemo {
 public static void main(String[] args) {
  Thread t1=new ThreadMy01();
  Thread t2=new ThreadMy02();
  
  t1.start();
  t2.start();

  
 }
}

class ThreadMy01 extends Thread{
 public static StringBuilder str=new StringBuilder();
 public void run(){
  String name=Thread.currentThread().getName();
  synchronized (str) {
   for(int i=0;i<5;i++){
    try {
     str.wait(300);//完全释放锁
     //Thread.sleep(300);//不释放锁
     str.append('a');
     System.out.println(name+str);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
   }  
  }
 }
}


//唤醒wait状态
class ThreadMy02 extends Thread{
 public void run(){
  synchronized (ThreadMy01.str) {
   for(int i=0;i<2;i++){
    try {
     Thread.sleep(2000);
     System.out.println("888");
    } catch (Exception e) {
     e.printStackTrace();
    }
   }
   //唤醒wait()状态
   ThreadMy01.str.notify();
  }
 }
}

运行结果:

888
888
Thread-0a
Thread-0aa
Thread-0aaa
Thread-0aaaa
Thread-0aaaaa

结果分析:

在运行以上代码时sleep虽然睡眠2秒,但是wait并没有 执行,说明sleep不会让出系统资源。

线程的生命周期:

在这里插入图片描述

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

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

相关文章

在Linux上安装Percona Toolkit工具

安装步骤 1. 下载安装包 下载地址&#xff1a;https://www.percona.com/software/database-tools/percona-toolkit 2.上传并解压 上传tar包到服务器&#xff0c;并通过tar -zxvf 文件名.tar.gz解压。工具在bin文件夹中&#xff0c;这个是免安装的。 3. 配置环境变量 配置…

安装OpenSearch

title: “安装opensearch” createTime: 2021-11-30T19:13:4508:00 updateTime: 2021-11-30T19:13:4508:00 draft: false author: “name” tags: [“es”,“安装”] categories: [“OpenSearch”] description: “测试的” 说明 基于Elasticsearch7.10.2 的 opensearch-1.1.…

gRPC之实现TLS通信加密_已设置图床

gRPC之实现TLS通信加密 "crypto/tls"包 “crypto/tls” 是 Go 编程语言中的一个包&#xff0c;用于实现 TLS&#xff08;传输层安全&#xff09;协议。TLS 协议用于加密和保护网络通信&#xff0c;通常用于保护敏感数据的传输&#xff0c;如密码、支付信息等。在 G…

详解--计算机存储相关(寄存器、CPU Cache、内存、外存)

CPU寄存器、高速缓冲存储器、主存储器、外存储器 1. 主存储器 参考链接–主存 参考链接–内存 主存储器简称 主存&#xff0c;又称 内存储器&#xff08;简称 内存&#xff09;。作用 暂时存放CPU中的运算数据。存放指令和数据&#xff0c;并能由中央处理器&#xff08;CPU&a…

什么是Service Worker?它在PWA中的作用是什么?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ Service Worker的作用是什么&#xff1f;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前…

1066 二级C语言-自定义函数

输入一个正数x和一个正整数n&#xff0c;求下列算式的值。要求定义两个调用函数&#xff1a; &#xff08;1&#xff09;fact(n)计算n的阶乘&#xff1b; &#xff08;2&#xff09;mypow(x,n)计算x的n次幂&#xff08;即xn&#xff09;&#xff0c;两个函数的返回值类型是do…

HEC-HMS和HEC-RAS水文模型、防洪评价报告编制及洪水建模、洪水危险性评价等相关案例解析

► HEC-RAS一维、二维建模方法及应用 【目标】&#xff1a; 1.掌握一维数学模型基本地形导入方法 2.掌握恒定流、非恒定流一维数学模型水流计算方法 3.掌握一维数学模型计算结果分析&#xff0c;水面线成果分析及调试&#xff1b;流速分布图输出方法 4.掌握一维数学模型增设构…

如何让一个uniform variable在多级shader中都起作用(类似C语言的全局变量)?

GLSL编程中通常设计多个shader&#xff0c;如vertex shader, fragment shader等等。在最近的某个项目中&#xff0c;我需要定义一个变量&#xff0c;该变量类似C语言中的全局变量&#xff0c;要同时在两个shader中都起作用。c - OpenGL Uniform Across Multiple Shaders - Stac…

2023-9-23 区间选点

题目链接&#xff1a;区间选点 #include <iostream> #include <algorithm>using namespace std;const int N 100010;int n;struct Range {int l, r;bool operator< (const Range &W) const{return r < W.r;} }range[N];int main() {scanf("%d"…

MyBatisPlus + ShardingJDBC 批量插入不返回主键ID

本文讲述一个由 ShardingJDBC 使用不当引起的悲惨故事。 一. 问题重现 有一天运营反馈我们部分订单状态和第三方订单状态无法同步。 根据现象找到了不能同步订单状态是因为 order 表的 thirdOrderId 为空导致的&#xff0c;但是这个字段为啥为空&#xff0c;排查过程比较波折…

NebulaGraph实战:2-NebulaGraph手工和Python操作

图数据库是专门存储庞大的图形网络并从中检索信息的数据库。它可以将图中的数据高效存储为点&#xff08;Vertex&#xff09;和边&#xff08;Edge&#xff09;&#xff0c;还可以将属性&#xff08;Property&#xff09;附加到点和边上。本文以示例数据集basketballplayer为例…

java的Map和Set集合

Set集合 一.HashSet HashSet 元素是无序的 向Hashset中添加元素时&#xff0c;是如何判断元素是否重复的: 添加元素时&#xff0c;如果用equals判断效率太低&#xff0c;因为equals是一个一个字符比较 HashSet底层用到hashCode和equals 一个内容&#xff1a;"sahdihwo&q…

FPGA 安装Quartus 13.1无法生成.sof文件

FPGA 安装Quartus 13.1无法生成.sof文件 安装环境编译无法生成 .sof文件分析原因 找资料1.第1篇文章2.第2篇文章 安装环境 Quarter II 13.0下载、安装、破解包括可能出现的几乎所有的问题详解野火FPGA安装视频 编译无法生成 .sof文件 分析原因 1.推测可能是破解失败。2.安装…

洛谷bfs题2---P1825 [USACO11OPEN] Corn Maze S

P1825 [USACO11OPEN] Corn Maze S import java.util.LinkedList; import java.util.Queue; import java.util.Scanner;public class Main {public static int N;//行public static int M;//列public static Queue<Integer> q new LinkedList<>();public static in…

变量、因子、缺失值、类型转换、剔除多余变量、随机抽样、用R使用SQL、trim、na.rm=TRUE、数据标准化应用

变量&#xff1a;名义型、有序型、连续型变量 名义型&#xff1a;普通事件类型&#xff0c;如糖尿病I型和糖尿病II型。 有序型&#xff1a;有顺序的事件类型&#xff0c;如一年级、二年级和三年级。 连续型&#xff1a;表示有顺序的数量&#xff0c;如年龄。 因子&#xff1a;…

现代架构设计:构建可伸缩、高性能的系统

文章目录 架构设计的基本原则1. 可伸缩性2. 可用性和容错性3. 性能4. 安全性5. 简单性 现代架构设计的关键概念1. 微服务架构2. 容器化3. 云原生4. 自动化和持续集成/持续交付&#xff08;CI/CD&#xff09; 构建可伸缩、高性能的系统的最佳实践1. 合理使用缓存2. 负载均衡3. 弹…

在Python中处理CSV文件的常见问题

当谈到数据处理和分析时&#xff0c;CSV&#xff08;Comma-Separated Values&#xff09;文件是一种非常常见的数据格式。它简单易懂&#xff0c;可以被绝大多数编程语言和工具轻松处理。在Python中&#xff0c;我们可以使用各种库和技巧来处理CSV文件&#xff0c;让我们一起来…

Server2101

B-1:数据库服务渗透测试 任务环境说明: 服务器场景:Server2101 服务器场景操作系统:未知(关闭连接) 1.通过分析靶机Server2101页面信息,寻找漏洞页面,将WEB服务存在SQL注入漏洞的页面名称作为Flag提交; nmap -p- 扫描发现靶机80和443端口有http、https服务 访问网站…

Nginx访问认证

访问认证 有时候&#xff0c;我们⼀些站点内容想要进⾏授权查看&#xff0c;只能输⼊账号密码之后才能访问&#xff0c;例如⼀些重要的内⽹平台&#xff0c;CRM &#xff0c; CMDB &#xff0c;企业内部 WIKI 等等。 htpasswd是Apache密码⽣成⼯具&#xff0c;Nginx⽀持auth_ba…

多卫星定位算法

多卫星定位算法 现已知有N(N>4)个卫星&#xff0c;每个卫星的坐标用 X s {X_s} Xs​表示&#xff0c;其对应的伪距用 r r r表示。 由于伪距不是准确的、真实的距离&#xff0c;它有所干扰。所以我们可以再根据三维空间中的距离公式&#xff0c;另外估计卫星和用户的距离为 …