1:数据安全问题

1.1:什么情况下会出现数据安全问题?

多个线程对同一个资源进行操作,并且操作资源的语句有多条。那么这个时候这些语句因为cpu的随机性,有可能被多个线程分开执行。导致数据安全问题。

例子:有3个人分别是你爸、你妈妈、你姐,去你的一个账户汇钱给你,每一个只能存3次,一次只能存100元。每存一次,请打显示出账户里的余额。代码体现:

 public class SaveMoneyDemo1 {

     public static void main(String[] args) {
SaveDemo1 s = new SaveDemo1();
Thread t1 = new Thread(s);
t1.setName("老爸");
Thread t2 = new Thread(s);
t2.setName("老妈");
Thread t3 = new Thread(s);
t3.setName("姐姐");
t1.start();
t2.start();
t3.start();
} } class SaveDemo1 implements Runnable{
private int sum = 0;
//要执行的代码块放在run方法里面。
public void run() {
//每个人能存三次,就是循环三遍
for(int i=0; i<3; i++){
sum+=100;
System.out.println(Thread.currentThread().getName()+"给你汇了100,目前账号共有 "+sum+" 元"); }
}
}
/**
* 执行结果:
老妈给你汇了100,目前账号共有 200 元
老妈给你汇了100,目前账号共有 400 元
老妈给你汇了100,目前账号共有 500 元
姐姐给你汇了100,目前账号共有 300 元
姐姐给你汇了100,目前账号共有 600 元
姐姐给你汇了100,目前账号共有 700 元
老爸给你汇了100,目前账号共有 200 元
老爸给你汇了100,目前账号共有 800 元
老爸给你汇了100,目前账号共有 900 元
*
*/

没有同步的汇款代码

运行结果好喜感。为什么会出现这种情况?分析:这三人存款是不需按照顺序和次数的,反正帮你存够三次就行了,所以用多线程更为合理。可是,打个比方:当你妈妈在存钱的时候钱是存进去了,在没来得及显示余额的时候你爸正好也把钱存了进去,这时候总金额连同你妈和你爸的加在一起了!所以显示出的金额会发生这样的情况。那么如何解决类似的情况呢?这就要限定一个人存一次就先把金额加上,不能让多人存完之后再一起加,如果这样那金额的显示就乱套了。这时候就要使用同步机制了。

1.2:解决方案: 同步机制

1.2.1:同步代码块。

synchronized(锁){//锁可以为任意对象。但是需要保证多个线程用的是同一把锁。

对同一个资源的操作语句。

}

1.2.2:同步方法的锁:

2.1:同步方法-----this

2.2:静态同步方法-----字节码文件对象。类名.class

 public class SaveMoneyDemo2 {

     public static void main(String[] args) {
SaveDemo2 s = new SaveDemo2();
Thread t1 = new Thread(s);
t1.setName("老爸");
Thread t2 = new Thread(s);
t2.setName("老妈");
Thread t3 = new Thread(s);
t3.setName("姐姐");
t1.start();
t2.start();
t3.start();
} } class SaveDemo2 implements Runnable{
private int sum = 0;
//要执行的代码块放在run方法里面。
public void run() {
//每个人能存三次,就是循环三遍
synchronized(this){
for(int i=0; i<3; i++){
sum+=100;
System.out.println(Thread.currentThread().getName()+"给你汇了100,目前账号共有 "+sum+" 元");
}
}
}
}

使用同步的数据安全的汇款

 1.3:如果加了同步,还出现数据安全问题,如何排查?

1.3.1:是否为同一把锁

1.3.2:访问资源的多条语句是否在同步中。

1.4:关于同步的拙劣理解:一件事先一口气做完!不让别人插手。(好像太牵强了)

2:死锁问题——互不释放资源(互相等待资源)

  2.1  需求:用程序来描述以下情况:一手交钱一手交货。商家与顾客两人都是很小气的人,顾客买商家的东西,商家收顾客的前,顾客说:先给我货我再给你钱;商家说:先给我钱我再给你货。最好的结局就是各自得到各自的东西。

2.2  分析:对于商家和客户来说和他们俩有关的不是钱就是货,而限制这两人的也就是钱和货。这样一来钱和货就可以看做是程序中的两个锁了。造成死锁的原因:同步代码嵌套!在平时开发时应避免同步嵌套!

 public class DeadLockDemo1 {
public static void main(String[] args) {
Thread t1 = new Customer1();
Thread t2 = new Seller1();
t1.start();
t2.start();
}
} class Customer1 extends Thread{
public static Object money = new Object();
@Override
public void run() {
//客户有钱
synchronized(money){
System.out.println("客户等商家给货");
//客户等货
synchronized (Seller1.goods) {
System.out.println("客户给商家钱");
}
}
}
} class Seller1 extends Thread{
public static Object goods = new Object();
@Override
public void run() {
//商家有货
synchronized (goods) {
System.out.println("商家等客户给钱");
//商家等钱
synchronized (Customer1.money) {
System.out.println("商家给客户货");
}
}
}
} /**
* 如果想结果暴露地更明显,可以使用sleep()方法
* 运行死锁的结果:
* 客户等商家给货
* 商家等客户给钱
*
*/

死锁示例代码

3:等待唤醒机制。

前面多个线程案例中,每个线程执行的操作是一样的。如果线程所执行的操作不一样呢?比如一个线程负责生产产品,另外一个线程负责消费产品。

 3.1:创建2个线程,2个线程的动作是不一样。比如说:一个生产者和一个消费者。

需求:生产者生产一个产品。消费者消费一个产品。这就涉及到了等待唤醒机制。当生产者生产一个产品后进入等待模式等待消费者来消费这个产品,当消费者消费了这个产品,发现没有产品了,消费者等待,叫生产者生产产品。生产者生产了产品则通知消费者。这就涉及到等待唤醒机制。

  3.2:等待唤醒机制。

等待唤醒机制必须是在同步中进行,因为等待和唤醒都是要通过锁来操作的,查看API就是的,wait()和notify()是属于Object的方法,任何对象都是可以作为锁的。

wait:让当前线程等待。在哪里等待的就在哪里醒过来。

notify() :唤醒其中一个等待的线程。

notifyAll():唤醒所有等待的线程

wait和sleep的区别:

1:sleep会拥有锁,而wait会释放锁。

2:sleep睡眠的时间是固定的,而wait等待的时间是不固定的。

3:sleep可以放在同步中,也可以不放在同步中。wait方法必须放在同步中。

 3.3:一个生产者和一个消费者的代码实现

 /*
* 生产者生产一个产品。
* 消费者消费一个产品。
* 生产者可以生产多个产品,但是一次只能生产一个产品。消费了才能生产。
* 消费者可以消费多个产品。但是一次只能消费一个 产品。生产有了产品才能消费。
*/
public class ProCusDemo1 {
public static Object lock = new Object();//创建一个对象作为锁
public static int num = 0;//产品数
public static void main(String[] args) {
Pro pro = new Pro();
Cus cus = new Cus();
pro.start();
cus.start();
} } class Pro extends Thread {
@Override
public void run() {
//不断生产,使用循环
while(true){
try {
Thread.sleep(100);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// System.out.println("111");
//操作同一数据——产品数(num),使用同步代码块,也可以是等待唤醒机制必须在同步在同步中进行
synchronized (ProCusDemo1.lock) {
//当有一个产品了,生产者就不用生产了
if(ProCusDemo1.num == 1){
try {
//不用生产的体现就是等待
ProCusDemo1.lock.wait();
// System.out.println("222");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
ProCusDemo1.num ++;//生产了一个产品
System.out.println("生产者生产了一个产品,现有:"+ProCusDemo1.num+" 个");
//当生产了一个产品之后就可以唤醒消费者消费了
ProCusDemo1.lock.notify();
}
}
}
} class Cus extends Thread {
@Override
public void run() {
while(true){
// System.out.println("333");
try {
Thread.sleep(100);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//多个线程操作同一数据使用同步
synchronized (ProCusDemo1.lock) {
if(ProCusDemo1.num == 0){
try {
ProCusDemo1.lock.wait();
// System.out.println("444");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
ProCusDemo1.num--;
System.out.println("消费者消费了一个产品,现有:"+ProCusDemo1.num+" 个");
ProCusDemo1.lock.notify();
}
} }
}

等待唤醒机制——生产消费

Java多线程(二)同步与等待唤醒的更多相关文章

  1. Java多线程02(线程安全、线程同步、等待唤醒机制)

    Java多线程2(线程安全.线程同步.等待唤醒机制.单例设计模式) 1.线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量 ...

  2. Java多线程的同步控制记录

    Java多线程的同步控制记录 一.重入锁 重入锁完全可以代替 synchronized 关键字.在JDK 1.5 早期版本,重入锁的性能优于 synchronized.JDK 1.6 开始,对于 sy ...

  3. Java多线程编程(同步、死锁、生产消费者问题)

    Java多线程编程(同步.死锁.生产消费): 关于线程同步以及死锁问题: 线程同步概念:是指若干个线程对象并行进行资源的访问时实现的资源处理保护操作: 线程死锁概念:是指两个线程都在等待对方先完成,造 ...

  4. java 多线程二

    java 多线程一 java 多线程二 java 多线程三 java 多线程四 线程中断: /** * Created by root on 17-9-30. */ public class Test ...

  5. Java多线程之同步集合和并发集合

    Java多线程之同步集合和并发集合 不管是同步集合还是并发集合他们都支持线程安全,他们之间主要的区别体现在性能和可扩展性,还有他们如何实现的线程安全. 同步集合类 Hashtable Vector 同 ...

  6. java基础(27):线程安全、线程同步、等待唤醒机制

    1. 多线程 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的. 我们通过一个案例,演示线程 ...

  7. Java多线程5:线程等待与唤醒

    原文:http://www.cnblogs.com/skywang12345/p/3479224.html wait(),notify(), notifyAll()等方法介绍在Object.java中 ...

  8. java多线程二之线程同步的三种方法

          java多线程的难点是在:处理多个线程同步与并发运行时线程间的通信问题.java在处理线程同步时,常用方法有: 1.synchronized关键字. 2.Lock显示加锁. 3.信号量Se ...

  9. Java多线程的同步机制(synchronized)

    一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,在 java里边就是拿到某个同步对象的锁(一个对象只有一把锁): 如果这个时候同步对象的锁被其他线程拿走了,他(这个 ...

随机推荐

  1. struts2 动态Action

    1.java 2.struts.xml struts2.5,默认关闭动态Action,着色的是开启和使用动态action 3.JSP 小结:访问时,用!后跟方法名的方法,方法返回值----->r ...

  2. VS2013的IDE开发使用便捷实用技巧----(补充)

    快捷键操作真的很高效.很酷······ 节省时间,提高开发效率 向人们展示可以惊讶到他们的功能,就像“我怎么就没发现”这种功能. 1. Peek View(本地查看程序源代码位置,便捷跳转) 可以在不 ...

  3. MySQL—练习2

    参考链接:https://www.cnblogs.com/edisonchou/p/3878135.html   感谢博主 https://blog.csdn.net/flycat296/articl ...

  4. Lucene索引的【增、删、改、查】

    前言 搞检索的,应该多少都会了解Lucene一些,它开源而且简单上手,官方API足够编写些小DEMO.并且根据倒排索引,实现快速检索.本文就简单的实现增量添加索引,删除索引,通过关键字查询,以及更新索 ...

  5. WPF定时刷新UI界面

    代码: using NHibernate.Criterion; using System; using System.Collections.Generic; using System.Collect ...

  6. sharepoint 2013 query slow

    计划: ==== 1. 调整SharePoint以及SQL端的网卡设置, 注意修改这些属性可能会导致网络暂时中断,但会很快恢复,不需要重启服务器. A. 以管理员权限运行CMD B. 关闭烟囱卸载状态 ...

  7. 初识阿里开源诊断工具Arthas

    上个月,阿里开源了一个名为Arthas的监控工具.恰逢近期自己在写多线程处理业务,由此想到了一个问题. 如果在本机开发调试,IDE可以看到当前的活动线程,例如IntelliJ IDEA,线程是运行还是 ...

  8. java学习笔记—Tomcat(9)

    1 目录结构 bin  二进制目录,主要存储的是一些启动和停止服务器的命令startup.bat conf  配置目录,server.xml web.xml lib  服务器软件使用的第三方的j ...

  9. Python(模块&包)

    参考:https://www.cnblogs.com/yuanchenqi/articles/5732581.html 在linux下给pycharm安装第三方库,需要在.bashrc中加: 因为对应 ...

  10. 爬虫3:requests库

      一个简单易用的http库,多用于第一步,爬取网站源码   简单例子 import requests   response = requests.get('https://www.baidu.com ...