首页 > 其他分享 >常见线程安全类

常见线程安全类

时间:2023-12-19 22:32:58浏览次数:32  
标签:安全类 void 常见 update 安全 线程 new public

常见线程安全类

  • String
  • Integer
  • StringBuffer
  • Random
  • Vector
  • Hashtable
  • java.util.concurrent 包下的类

这里说它们是线程安全的是指,多个线程调用它们同一个实例的某个方法时,是线程安全的。也可以理解为

Hashtable table = new Hashtable();
new Thread(()->{
 table.put("key", "value1");
}).start();
new Thread(()->{
 table.put("key", "value2");
}).start();
  • 它们的每个方法是原子的
  • 注意它们多个方法的组合不是原子的,见后面分析

线程安全类方法的组合

分析下面代码是否线程安全?

Hashtable table = new Hashtable();
// 线程1,线程2
if( table.get("key") == null) {
 table.put("key", value);
}

常见线程安全类_并发

由上图可见并不是线程安全的

不可变类线程安全性

String、Integer 等都是不可变类,因为其内部的状态不可以改变,因此它们的方法都是线程安全的

有同学或许有疑问,String 有 replace,substring 等方法【可以】改变值啊,那么这些方法又是如何保证线程安全的呢?

public class Immutable{
 private int value = 0;
 public Immutable(int value){
 this.value = value;
 }
 public int getValue(){
 return this.value;
 }
}

如果想增加一个增加的方法呢?

public class Immutable{
 private int value = 0;
 public Immutable(int value){
 this.value = value;
 }
 public int getValue(){
 return this.value;
 }
 
 public Immutable add(int v){
 return new Immutable(this.value + v);
 } 
}

实例分析

例1:

public class MyServlet extends HttpServlet {
 // 是否安全? HashMap不是线程安全的,hashtable是线程安全的
 Map<String,Object> map = new HashMap<>();
 // 是否安全?是的,string类不可变
 String S1 = "...";
 // 是否安全? 是的,string类不可变
 final String S2 = "...";
 // 是否安全?不是线程安全的
 Date D1 = new Date();
 // 是否安全?也不是线程安全的 final只能保证引用不可变,内容 年月日是可以修改的
 final Date D2 = new Date();
 
 public void doGet(HttpServletRequest request, HttpServletResponse response) { // 使用上述变量
 }
}

例2:

public class MyServlet extends HttpServlet {
 // 是否安全?不是线程安全的,多个线程可以共享
 private UserService userService = new UserServiceImpl();
 
 public void doGet(HttpServletRequest request, HttpServletResponse response) {
 userService.update(...);
 }
}
public class UserServiceImpl implements UserService {
 // 记录调用次数
 private int count = 0;
 
 public void update() {
 // ...
 count++;
 }
}

例3:

@Aspect
@Component
public class MyAspect {
 // 是否安全?不是线程安全的 start是成员变量,可能会出现多个线程共享(可以改成环绕通知,将成员变量改为局部变量)
 private long start = 0L;
 
 @Before("execution(* *(..))")
 public void before() {
 start = System.nanoTime();
 }
 
 @After("execution(* *(..))")
 public void after() {
 long end = System.nanoTime();
 System.out.println("cost time:" + (end-start));
 }
}

例4:

public class MyServlet extends HttpServlet {
 // 是否安全 是线程安全 是私有的成员变量,没有其他地方可以修改
 private UserService userService = new UserServiceImpl();
 
 public void doGet(HttpServletRequest request, HttpServletResponse response) {
 userService.update(...);
 }
}
public class UserServiceImpl implements UserService {
 // 是否安全 是线程安全的
 private UserDao userDao = new UserDaoImpl();
 
 public void update() {
 userDao.update();
 }
}
public class UserDaoImpl implements UserDao { 
 public void update() {
 String sql = "update user set password = ? where username = ?";
 // 是否安全 是线程安全的 Connection是局部变量
 try (Connection conn = DriverManager.getConnection("","","")){
 // ...
 } catch (Exception e) {
 // ...
 }
 }
}

例5:

public class MyServlet extends HttpServlet {
 // 是否安全 是线程安全 是私有的成员变量,没有其他地方可以修改
 private UserService userService = new UserServiceImpl();
 
 public void doGet(HttpServletRequest request, HttpServletResponse response) {
 userService.update(...);
 }
}
public class UserServiceImpl implements UserService {
 // 是否安全 是线程安全的 没有成员变量
 private UserDao userDao = new UserDaoImpl();
 
 public void update() {
 userDao.update();
 }
}
public class UserDaoImpl implements UserDao {
 // 是否安全 不是线程安全的 会被多个线程共享
 private Connection conn = null;
 public void update() throws SQLException {
 String sql = "update user set password = ? where username = ?";
 conn = DriverManager.getConnection("","","");
 // ...
 conn.close();
 }
}

例6:

public class MyServlet extends HttpServlet {
 // 是否安全 是线程安全的
 private UserService userService = new UserServiceImpl();
 
 public void doGet(HttpServletRequest request, HttpServletResponse response) {
 userService.update(...);
 }
}
public class UserServiceImpl implements UserService { 
 public void update() {    
 UserDao userDao = new UserDaoImpl();
 userDao.update();
 }
}
public class UserDaoImpl implements UserDao {
 // 是否安全 是线程安全的
 private Connection = null;
 public void update() throws SQLException {
 String sql = "update user set password = ? where username = ?";
 conn = DriverManager.getConnection("","","");
 // ...
 conn.close();
 }
}

例7:

public abstract class Test {
 
 public void bar() {
 // 是否安全 不是线程安全的
 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 foo(sdf);
      }
 
 public abstract foo(SimpleDateFormat sdf);
 
 
 public static void main(String[] args) {
 new Test().bar();
 }
}

其中 foo 的行为是不确定的,可能导致不安全的发生,被称之为外星方法

public void foo(SimpleDateFormat sdf) {
 String dateStr = "1999-10-11 00:00:00";
 for (int i = 0; i < 20; i++) {
 new Thread(() -> {
 try {
 sdf.parse(dateStr);
 } catch (ParseException e) {
 e.printStackTrace();
 }
 }).start();
 }
}

标签:安全类,void,常见,update,安全,线程,new,public
From: https://blog.51cto.com/AmbitionGarden/8895384

相关文章

  • C++11 多线程
    文章参考:C++教程|爱编程的大丙(subingwen.cn)C++11的原子量与内存序浅析-兔晓侠-博客园(cnblogs.com)从C++11起,C++为用户提供一套新的多线程类。线程相关操作头文件:thread#include<thread>一.std::thread1.初始化和析构默认构造函数:原型:thread()noexce......
  • 多线程
    sleep方法:sleep方法使当前线程暂停执行指定的时间,然后继续执行。在线程休眠期间,它不会释放任何锁资源。sleep方法主要用于控制线程的执行速度或等待某个条件成立。Thread.sleep(5000);//休眠5秒钟Threadt1=newThread(newRunnable(){@Overridepubl......
  • 无涯教程-Java - 线程控制函数
    核心Java提供了对多线程程序的完全控制,您可以开发一个多线程程序,该程序可以根据您的要求完全挂起,恢复或停止。您可以对线程对象使用各种静态方法来控制其行为。下表列出了这些方法-Sr.No.Method&Remark1publicvoidsuspend()该方法将线程置于挂起状态,可以使用resume()......
  • 无涯教程-Java - 处理线程死锁函数
    死锁描述了一种情况,其中两个或多个线程永远被阻塞,互相等待,当多个线程需要相同的锁但以不同的顺序获得它们时,就会发生死锁。Java多线程程序可能会遇到死锁情况,因为synchronized关键字会导致正在执行的线程在等待与指定对象关联的锁时被阻塞。这是一个示例。publicclassTestT......
  • 【FAQ】运动健康服务云侧数据常见问题及解答
    目录Q1:v2接口相比于v1接口传参及返回的数据格式有变化吗?是否可以直接将v1接口改成v2接口?Q2:如何获取采集健康数据的穿戴设备信息?Q3:如何处理非华为手机产生的步数调用采样明细接口查询不到数据,并且收不到订阅事件通知的问题?Q4:数据订阅接口的按条件删除订阅记录中,可以同时删除多个订阅......
  • SMT贴片生产加工中常见的危险和防护措施
    在SMT贴片生产加工中,存在许多潜在的危险,需要采取相应的防护措施来保证员工的安全和生产环境的安全,下面由英特丽列罗几种常见的危险及防护措施。1.静电危险静电可引起灵敏的电子元件损坏,甚至导致火灾。为了防止静电,员工应佩戴防静电服,防静电鞋和手套,操作过程中要与地线相连。工作区......
  • 【FAQ】运动健康服务云侧数据常见问题及解答
    目录Q1:v2接口相比于v1接口传参及返回的数据格式有变化吗?是否可以直接将v1接口改成v2接口?Q2:如何获取采集健康数据的穿戴设备信息?Q3:如何处理非华为手机产生的步数调用采样明细接口查询不到数据,并且收不到订阅事件通知的问题?Q4:数据订阅接口的按条件删除订阅记录中,可以同时删除多......
  • mysql 常见错误
    Datatruncation:Datatoolongforcolumn'subtitle2'atrow1报错:.MysqlDataTruncation:Datatruncation:Datatoolongforcolumn1、可能数据库中的字符集的编码与写代码的页面的编码不相符合;(一般为utf-8)2、可能数据库字段的长度太小,不满足要求;che......
  • 【多线程笔记】Channel
    在面对生产者-消费者的场景下,netcore提供了一个新的命名空间System.Threading.Channels来帮助我们更高效的处理此类问题,有了这个Channels存在,生产者和消费者可以各自处理自己的任务而不相互干扰,有利于两方的并发处理,这篇文章我们就来讨论下如何使用System.Threading......
  • 大语言模型训练数据常见的4种处理方法
    本文分享自华为云社区《浅谈如何处理大语言模型训练数据之一常见的数据处理方法》,作者:码上开花_Lancer。大语言模型训练需要数万亿的各类型数据。如何构造海量“高质量”数据对于大语言模型的训练具有至关重要的作用。虽然,截止到2023年9月为止,还没有非常好的大模型的理论分析......