多线程下的数据安全(多线程如何保证数据安全)

  本篇文章为你整理了多线程下的数据安全(多线程如何保证数据安全)的详细内容,包含有多线程数据安全问题 多线程如何保证数据安全 多线程安全性问题 多线程 安全 多线程下的数据安全,希望能帮助你了解 多线程下的数据安全。

  多线程下的数据安全

  ​ 再以后的开发中,我们的项目都是运行在服务器中,而服务器已经将线程的定义,线程对象的创建,线程的启动等,都已经实现完了。我们需要做的就是把编写的程序放到一个多线程的环境下运行!确保这些数据在运行时都是安全的

  一、线程存在安全的三个条件

  多线程并发

  有共享数据

  共享数据有修改的行为

  只要满足上面三个条件,线程就会存在安全问题

  二、线程同步机制

  怎么去解决线程安全问题,我们采取线程排队执行来让它不能并发来解决!

  这种机制被称为:线程同步机制

  线程同步会牺牲一部分效率来保证数据安全,因为数据安全比效率更为重要

  三、编程模型

  1.同步编程模型

  ​ 线程t1和线程t2,在t1执行的时候,必须等待t2线程执行结束。或者在t2执行的时候,必须等待t1线程执行结束。两个线程发生了等待关系,这就是同步编程模型,效率较低,同步就是排队执行!

  2.异步编程模型

  ​ 线程t1和线程t2,各自执行,t1不干涉t2,t2不干涉t1。两者互不干扰,不需要进行等待,这种编程模型叫做:异步编程模型,效率较高。异步就是并发

  四、线程安全代码示例

  模拟两个线程同时对一个账户进行存取款操作

  代码示例:

  

/*

 

  public class Account {

   //账户

   private String snoid;

   //余额

   private double balance;

   public Account(String snoid, double balance) {

   this.snoid = snoid;

   this.balance = balance;

   public String getSnoid() {

   return snoid;

   public void setSnoid(String snoid) {

   this.snoid = snoid;

   public double getBalance() {

   return balance;

   public void setBalance(double balance) {

   this.balance = balance;

   public Account() {

   //取款的构造方法

   public void withdraw(Double money){

   //取款之前的余额

   double before=this.getBalance();

   //取款之后的余额

   double after=before-money;

   //更新余额

   this.setBalance(after);

  

 

  创建一个线程:线程中run方法,一次取5000块钱

  

public class AccountThread extends Thread{

 

   //两个线程必须共享一个账户对象

   private Account act;

   //通过构造方法传递过来账户对象

   public AccountThread(Account act){

   this.act=act;

   public void run() {

   //run方法的执行表示取款操作

   double money=5000;

   act.withdraw(money);

   System.out.println(Thread.currentThread().getName()+"账户"+act.getSnoid()+"取款成功,您的当前余额为"+act.getBalance());

  

 

  测试一下:

  

public class AccountTest {

 

   public static void main(String[] args) {

   Account act=new Account("act-1",10000);

   //创建连个线程

   Thread t1=new AccountThread(act);

   Thread t2=new AccountThread(act);

   t1.setName("t1");

   t2.setName("t2");

   t1.start();

   t2.start();

  

 

  

 //如果一个线程执行,但是执行过取款操作,没有执行更新操作

 

   //这时候,t2进来执行,获取到的余额还是最初的!所以这种并发的程序有一定的风险

  

 

  例如:这样

  我们明明调用了两个线程去执行run方法,应该是一次取5000,第二次应该是0才对。那么现在出现这种情况!说明数据是不安全的

  但是这也是有概率,现在我们放大这个概率,让余额在执行更新操作前睡1s,那么就相当于低于个执行的线程,执行完取款操作之后,等了一下第二个线程。那么第二个先读取余额的时候还是读取到的10000,现在无论执行多少次,无论是哪个先执行都是上图中的结果!

  五、synchronize同步代码块

  ​ 那么为了解决上述问题,怎么去实现多个线程执行同步操作呢。只能使用我们上面说的排队了,这里就需要使用到synchronize同步代码块。
 

  ** synchronized (){
 

  ​ //线程同步代码块
 

  }**

  ​ 小括号中的数据必须是线程共享的数据,才能达到多线程排队
 

  ​ 需要那几个线程同步就写哪几个线程的共享对象
 

  ​ 例如,在这,我们t1对象和t2对象的共享对象就是this

  在java中,任何一个对象都有一把锁,其实这把锁就是标记。100个对象100把锁,一个对象一把锁!

  代码的执行原理:

  ​ 1.假设t1和t2线程并发,开始执行一下代码的时候,有一个先后顺序
 

  ​ 2.假设t1先执行,遇到了synchronized,这个时候自动找“后面共享对象”的对象锁,
 

  ​ 找到之后,并占有这把锁,然后执行同步代码块中的程序,在程序执行过程中是一直占有
 

  ​ 这把锁的。指代同步代码块改变,这把锁才会释放
 

  ​ 3.假设t1已经占有这把锁,此时t2也遇到synchronized关键字,也会去占用后面共享对象的这把锁。
 

  ​ 结果这把锁被t1占有,t2只能在同步代码块中等待t1的结束,直到t1把同步代码块执行结束,t1会归还
 

  ​ 这把锁此时t2终于等到这把锁,然后t2占有这把锁,进入同步代码块执行程序

  

注意:

 

   共享对象一定选择好,这个共享对象一定是你需要排队执行的这些线程对象所共享的

  

 

  代码示例:

  

/*

 

  public class Account {

   //账户

   private String snoid;

   //余额

   private double balance;

   public Account(String snoid, double balance) {

   this.snoid = snoid;

   this.balance = balance;

   public String getSnoid() {

   return snoid;

   public void setSnoid(String snoid) {

   this.snoid = snoid;

   public double getBalance() {

   return balance;

   public void setBalance(double balance) {

   this.balance = balance;

   public Account() {

   //取款的构造方法

   public void withdraw(Double money){

   //取款之前的余额

   synchronized (this){

   double before=this.getBalance();

   //取款之后的余额

   double after=before-money;

   try {

   Thread.sleep(1000);

   } catch (InterruptedException e) {

   e.printStackTrace();

   //更新余额

   //如果一个线程执行,但是执行过取款操作,没有执行下面这样的更新

   //这时候,t2进来执行,获取到的余额还是最初的!所以这种并发的程序有一定的风险

   this.setBalance(after);

  

 

  输出:

  

t1账户act-2取款成功,您的当前余额为5000.0

 

  t2账户act-2取款成功,您的当前余额为0.0

  

 

  七、存在线程安全的变量

  ​ java中有三大变量!

  实例变量:在堆中

  静态变量:在方法区中

  局部变量:在栈中

  局部变量永远不会存在线程安全问题,因为局部变量在栈中,永远不会共享!

  实例变量在堆中,堆只有一个,静态变量在方法区中,方法区也只有一个

  堆和方法区都是共享的,所以可能存在线程安全问题!

  局部变量以及常量都不会存在线程安全问题,成员变量可能会存在线程安全问题!

  如果使用局部变量:
 

  建议使用StringBuilder,因为局部变量不存在线程安全问题,选择StringBuilder效率比StringBuffer效率更高!

  ArrayList是非线程安全的

  Vector是线程安全的

  HashMap HashSet是非线程安全的

  Hashtable是线程安全的

  以上就是多线程下的数据安全(多线程如何保证数据安全)的详细内容,想要了解更多 多线程下的数据安全的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: