数据安全

  • 关于多线程并发环境下,数据的安全问题
  • 为什么这个是重点?以后在开发中,我们的项目都是运行在服务器当中,而服务器已经将线程的定义,线程对象的创建,线程的启动等,都已经实现完了。这些代码我们都不需要编写.
  • 最重要的是:你要知道,你编写的程序需要放到一个多线程的环境下运行,你更需要关注的是这些数据:在多线程并发的环境下是否是安全的。(重点:***** )
  • 什么时候数据在多线程并发的环境下会存在安全问题呢?
  • 三个条件:条件1:多线程并发,条件2:有共享数据,条件3:共享数据有修改的行为.
    满足以上3个条件之后,就会存在线程安全问题.
  • 怎么解决线程安全问题:线程同步机制
  • 线程排队执行,会牺牲一部分效率,但数据安全是第一位的
  • 异步编程模型:线程t1和线程t2,各自执行各自的,t1不管t2, t2不管t1, 谁也不需要等谁,这种编程模型叫做:异步编程模型。其实就是:多线程并发( 效率较高。)异步就是并发。
  • 同步编程模型:线程t1和线程t2,在线程t1执行的时候,必须等待t2线程执行结束,或者说在t2线程执行的时候,必须等待t1线程执行结束,两个线程之间发生了等待关系,这就是同步编程模型。效率较低。线程排队执行。同步就是排队。

synchronized()

编写程序,两个线程同时对一个账户进行取款操作。

Account类

package bankSystem;/*** 不适用线程同步机制,多线程对同一个银行账户取款,一定会出问题 使用线程同步机制,解决线程安全问题*/
public class Account {// 账号private String actno;// 余额private double balence;public Account() {}public Account(String actno, double balence) {super();this.actno = actno;this.balence = balence;}public String getActno() {return actno;}public void setActno(String actno) {this.actno = actno;}public double getBalence() {return balence;}public void setBalence(double balence) {this.balence = balence;}// 取款的方法/*** 以下代码,线程必须排队,不能并发 线程同步机制的语法块:synchronized(共享对象){}* 1、小括号里面的数据必须是多线程共享的数据,才能达到多线程排队 2、()内内容写什么:多线程共享的对象 那要看你想让哪些线程同步。 假设t1. t2.* t3. t4. t5 ,有个线程,你只希望t1 t2 t3排队, t4 t5不需要排B。怎么办? 这里共享对象是共账户对象,所以可以写this* *//*** synchronized出现在实例方法上,一定锁的是this,所以这种方式不灵活。* 还会导致整个方法体都想需要同步,程序执行效率降低,所以这种方法不常用* 当锁的是this时,可以使用用来简化代码书写* * @param money*/public synchronized void withdraw(double money) {//synchronized (this) {//synchronized (actno) {//在字符串常量池中,所有线程都会同步//synchronized ("a") {// t1,t1是两个栈,并发执行这个方法,两个栈操作堆中的一个对象// 取款之前的余额double before = this.getBalence();// 取款之后的余额double after = before - money;// 模拟一下网络延迟1秒,一定会发生问题try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}// 更新余额this.setBalence(after);//}}}

AccountThread类

package bankSystem;public class AccountThread extends Thread {// 连个线程必须共享同一个账户对象private Account act;// 通过构造方法传递过来账户对象public AccountThread(Account act) {super();this.act = act;}// 执行取款操作public void run() {// 假设取款5kdouble money = 5000;act.withdraw(money);System.out.println("对线程:" + Thread.currentThread().getName() + " 取款,账户:" + act.getActno() + " 取款成功,余额:"+ act.getBalence());}}

Test类

package bankSystem;public class Test {public static void main(String[] args) {Account act = new Account("act-001", 10000);Thread t1 = new AccountThread(act);Thread t2 = new AccountThread(act);// 设置name;t1.setName("t1");// 设置t1优先级,默认优先级为5t1.setPriority(8);t2.setName("t2");// 启动线程取款t1.start();t2.start();}
}
  • 如果使用局部变量的话:建议使用: stringBuilder。因为局部变量不存在线程安全问题。选择stringBuilder。stringBuffer效率比较低。
    ArrayList是非线程安全的。
    Vector是线程安全的.
    HashMap,Hashset是非线程安全的.
    Hashtable是线程安全的.
  • synchronized()三种写法:
  • 第一种:同步代码块
synchronized (线程共享对象) {同步代码块;
}
  • 第二种:.在实例方法上使用synchronized,表示共享对象一定是this
    并且同步代码块是整个方法体。
  • 第三种:在静态方法上使用synchronized表示找类锁。类锁永远只有1把,就算创建了100个对象,那类锁也只有一把。
    对象锁: 1个对象1把锁,100个对象100把锁.
    类锁: 100个对象,也可能只是1把类锁。
  • 面试题
    1、doOther()方法的执行需要等待doSome()方法执行结束吗?不需要,因为doOther()方法没有synchronized
package threadSafe;public class Exam01 {public static void main(String[] args) {MyClass ma = new MyClass();Thread t1 = new MyThread(ma);Thread t2 = new MyThread(ma);t1.setName("t1");// t1.setPriority(7);t2.setName("t2");t1.start();// 保证t1线程先执行try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}t2.start();}
}class MyThread extends Thread {private MyClass mc;public MyThread(MyClass mc) {this.mc = mc;}@Overridepublic void run() {// TODO Auto-generated method stubsuper.run();if (Thread.currentThread().getName().equals("t1")) {mc.doSome();}if (Thread.currentThread().getName().equals("t2")) {mc.doOther();}}
}class MyClass {//synchronized 出现在实例方法上,表示锁thispublic synchronized void doSome() {System.out.println("doSome begin!");try {Thread.sleep(1000 * 10);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("doSome over!");}public void doOther() {System.out.println("doOther begin!");System.out.println("doOther over!");}
}
/**
doSome begin!
doOther begin!
doOther over!
doSome over!
*/

2、doOther()方法的执行需要等待doSome()方法执行结束吗?需要,因为doOther()方法有synchronized

package threadSafe;public class Exam02 {public static void main(String[] args) {MyClass ma = new MyClass();Thread t1 = new MyThread(ma);Thread t2 = new MyThread(ma);t1.setName("t1");// t1.setPriority(7);t2.setName("t2");t1.start();// 保证t1线程先执行try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}t2.start();}
}class MyThread extends Thread {private MyClass mc;public MyThread(MyClass mc) {this.mc = mc;}@Overridepublic void run() {// TODO Auto-generated method stubsuper.run();if (Thread.currentThread().getName().equals("t1")) {mc.doSome();}if (Thread.currentThread().getName().equals("t2")) {mc.doOther();}}
}class MyClass {public synchronized void doSome() {System.out.println("doSome begin!");try {Thread.sleep(1000 * 10);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("doSome over!");}public synchronized void doOther() {System.out.println("doOther begin!");System.out.println("doOther over!");}
}

3、doOther()方法的执行需要等待doSome()方法执行结束吗?需要,因为doOther()方法的this和doSome()的this指向不一样,对象有两个

package threadSafe;public class Exam03 {public static void main(String[] args) {MyClass ma = new MyClass();MyClass ma1 = new MyClass();Thread t1 = new MyThread(ma);Thread t2 = new MyThread(ma1);t1.setName("t1");// t1.setPriority(7);t2.setName("t2");t1.start();// 保证t1线程先执行try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}t2.start();}
}class MyThread extends Thread {private MyClass mc;public MyThread(MyClass mc) {this.mc = mc;}@Overridepublic void run() {// TODO Auto-generated method stubsuper.run();if (Thread.currentThread().getName().equals("t1")) {mc.doSome();}if (Thread.currentThread().getName().equals("t2")) {mc.doOther();}}
}class MyClass {public synchronized void doSome() {System.out.println("doSome begin!");try {Thread.sleep(1000 * 10);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("doSome over!");}public synchronized void doOther() {System.out.println("doOther begin!");System.out.println("doOther over!");}
}

4、doOther()方法的执行需要等待doSome()方法执行结束吗?需要,因为synchronized出现在静态方法上,是类锁,类锁不管创建了几个对象,锁都只有一把

package threadSafe;public class Exam04 {public static void main(String[] args) {MyClass ma = new MyClass();MyClass ma1 = new MyClass();Thread t1 = new MyThread(ma);Thread t2 = new MyThread(ma1);t1.setName("t1");// t1.setPriority(7);t2.setName("t2");t1.start();// 保证t1线程先执行try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}t2.start();}
}class MyThread extends Thread {private MyClass mc;public MyThread(MyClass mc) {this.mc = mc;}@Overridepublic void run() {// TODO Auto-generated method stubsuper.run();if (Thread.currentThread().getName().equals("t1")) {mc.doSome();}if (Thread.currentThread().getName().equals("t2")) {mc.doOther();}}
}class MyClass {    public synchronized static void doSome() {System.out.println("doSome begin!");try {Thread.sleep(1000 * 10);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("doSome over!");}public synchronized static void doOther() {System.out.println("doOther begin!");System.out.println("doOther over!");}
}

死锁

示例:

package threadSafe;/*** 死锁代码要会写。一般面试官要求你会写。 * 只有会写的,才会在以后的开发中注意这个事儿。 因为死锁很难调试*/
public class DeadLock {public static void main(String[] args) {Object o1 = new Object();Object o2 = new Object();Thread t1 = new MyThread1(o1, o2);Thread t2 = new MyThread2(o1, o2);t1.start();t2.start();}
}class MyThread1 extends Thread {Object o1;Object o2;public MyThread1(Object o1, Object o2) {super();this.o1 = o1;this.o2 = o2;}@Overridepublic void run() {// 死锁,synchronized在开发过程中,最后不要嵌套使用,很有可能造成死锁synchronized (o1) {try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}synchronized (o2) {}}super.run();}}class MyThread2 extends Thread {Object o1;Object o2;public MyThread2(Object o1, Object o2) {super();this.o1 = o1;this.o2 = o2;}@Overridepublic void run() {synchronized (o2) {try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}synchronized (o1) {}}super.run();}
}

如何解决线程安全问题:

  • 一上来就使用synchronized吗?
  • 不是,synchronized会让程序的执行效率降低,用户体验不好。系统的用户吞吐量降低。用户体验差。在不得已的情况下再选择线程同步机制。
  • 第一种方案:尽量使用局部变量代替"实例变量和静态变量”。
  • 第二种方案:如果必须是实例变量,那么可以考虑创建多个对象,这样实例变量的内存就不共享了。(一个线程对应1个对象,100个线程对应100个对象,对象不共享,就没有数据安全问题了。)
  • 第三种方案:如果不能使用局部变量,对象也不能创建多个,这个时候就只能选择synchronized了。线程同步机制.

java基础 day14数据安全,银行账户取款例子,synchronized()使用、面试题,死锁,线程安全相关推荐

  1. java基础案例3-2银行存取款

    //菜单 package com.itheima; import java.util.Scanner;public class Main{public static Fun nb = new Fun( ...

  2. java模拟简单的银行账户,可用于存取款,查询业务操作

    ** java模拟简单的银行账户,可用于存取款,查询账户信息,银行查询当前客户数量操作 ** 本篇的内容关于:创建一个银行账户Account类,实现存款(deposit).取(withDraw)和查询 ...

  3. Java基础day14

    Java基础day14 Java基础day14-集合 1.Collection集合 1.1集合体系结构 1.2Collection集合概述和基本使用 1.3Collection集合的常用方法 1.4C ...

  4. java模拟银行存取_JAVA基础案例 模拟银行存取款业务

    模拟银行存取款业务 编写一个Java应用程序,模拟网上银行登录及存取款业务.登录时需判断银行卡号和银行卡密码,当输入的卡号和密码都正确时,登录成功,提示当前登录的账户名,并进入下一步选择操作类型.操作 ...

  5. java模仿银行账务业务_Java基础案例 - 模拟银行存取款业务

    博学谷--让IT教学更简单,让IT学习更有效 模拟银行存取款业务 编写一个Java应用程序,模拟网上银行登录及存取款业务.登录时需判断银行卡号和银行卡密码,当输入的卡号和密码都正确时,登录成功,提示当 ...

  6. Java实验2【银行存取款程序设计实验】

    文章目录 前言 一.任务介绍 1.任务描述 2.运行结果 3.任务目标 4.实现思路 二.程序实现 1.代码 2.实验结果(包括输入数据和输出结果) 总结 前言 记录学习中写的Java实验,我这里用的 ...

  7. 信息系统开发(JAVA)设计一个银行账户类

    实验要求: 设计一个银行账户类,其中包括: • 账户信息,如帐号.姓名.开户时间.身份证号码等. • 存款方法. • 取款方法. • 其他方法如"查询余额"和"显示账户信 ...

  8. 基于Java语言实现模拟银行存取款业务系统

    资源下载地址:https://download.csdn.net/download/sheziqiong/85820969 1.项目简介 本项目的主要功能是模拟银行的存取款业务,当用户登录时需判断银行 ...

  9. java存款程序_JAVA实现账户取款和存款操作

    这篇文章主要介绍了JAVA实现账户取款和存款操作,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 JAVA 编写一个程序完成从某账户取款和存款的操作 ...

最新文章

  1. Java - 网络编程(NetWork)
  2. 深度估计相关原理(计算机视觉和深度学习基础)
  3. 【opencv系列03】OpenCV4.X视频捕获与显示
  4. Attribute is missing the Android namespace prefix
  5. subline text 快捷键
  6. 使用flask调用接口去加载模型和数据集,避免每次运行都会重复加载数据集或模型,节约大量等待时间
  7. endnote无法同步原因_endnote不能同步(endnote retrieving references)的解决方法
  8. Android开发笔记(四十一)Service的生命周期
  9. WebService学习总结(一)——WebService的相关概念
  10. Thinkpad x200 X201拆机换风扇教程 实图
  11. 如何解决MySQL闪退
  12. C++原子量,内存序,无锁并发
  13. Python基础 Zero to Hero面向对象编程(一)
  14. HTML期末作业-我的家乡网页作业
  15. 相机XD卡格式化后,照片恢复
  16. SOC上的总线真的是总线?
  17. Markdown 内如何使用表情符号
  18. 最新百家姓-你排老几
  19. 比特大陆面临破产,吴忌寒:兄弟,把你简历寄过来
  20. 如何一次高效的插入200MB(50万条)的insert语句

热门文章

  1. 关于员工激励的思考-期望理论
  2. 服务器2016系统装完卡logo进不去,win10系统开机卡在logo画面_网站服务器运行维护...
  3. 2019东南大学计算机考研录取,东南大学2019年硕士研究生拟录取名单公示-不带成绩...
  4. 我见过最NB的鼠标-鼠标放进PC卡插槽 惠普卡片蓝牙鼠试用
  5. html上图片用js绘制点,用 js + html 描图 与画箭头
  6. 数据结构概述3 对称矩阵、树和二叉树
  7. 如何在微信H5页面链接跳转到第三方小程序的任意页面?
  8. 【转载】AE表达式中英文对照
  9. Chapter 76 - 89
  10. unity编辑器一些设置