Java------线程并发问题

初识并发问题

请添加图片描述

什么是并发操作

并发操作是指同一时间可能有多个用户对同一个数据进行读写操作

并发操作对数据的影响

如果对并发操作不做任何控制的话,会造成数据的不完整,可能造成读脏数据,不可重复读,丢失修改还能有幻读

对数据不完整性的举例

(1) 丢失修改

当两个或多个事务(或两个或多个用户)选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题。每个事务都不知道其它事务的存在(或每个用户操作时并不会考虑同一时刻是否有别的用户进行着同样的操作)。最后的更新将重写由其它事务所做的更新,这将导致数据丢失。

选课:学生A、学生B、课程1的余量=20

a.学生A选择课程1时,先读出课程余量20

b.然而同一时刻(也可是不同时刻,只要在学生A更新数据之前),学生B也读出了课程1的余量20,

c.学生A选择此课程,课程1余量-1,写入数据库,此时课程1的余量=19;

d.学生B选择此课程,课程1余量-1(因为之前读出的课程1余量为20,-1后为19),写入数据库,此时课 程1的余量=19;

课程余量=19 数据正确吗?不正确。实际情况课程余量应更新为18;——B的修改覆盖了A的修改

(2) 读脏数据

当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,

另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个

事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。

1.张三的工资为2000,元 老板把张三的工资改为了8000元(但未提交事务)

2.张三查看自己的工资 ,发现工资变为了8000元

3.而后老板发现改错了,回滚了事务,张三的工资又变回了2000元

​ 那么,张三读取的工资8000元就是脏数据。

(3) 不可重复读

当第二个事务多次访问同一行而且每次读取不同的数据时,会发生不一致的分析问题。不一致的分析与未确认的相关性类似,因为其它事务也是正在更改第二个事务正在读取的数据。然而,在不一致的分析中,第二个事务读取的数据是由已进行了更改的事务提交的。而且,不一致的分析涉及多次(两次或更多)读取同一行,而且每次信息都由其它事务更改;因而该行被非重复读取。

例子1:事务T1、事务T2、张三的工资=1000

a.事务T1中,张三读取了自己的工资为1000元,操作并没有完成

b.此时(事务T1读取了张三工资为1000元)事务2中,修改了张三的工资为2000元,并提交了事务.

c.此时(事务T1读取了张三工资为1000元,事务T2修改了张三的工资为2000元)在事务1中,张三再次读 取自己的工资时,工资变为了2000

例如:下面代码发现问题:多线程操作同一个资源的情况下,线程不安全,数据紊乱

package Practise.Demo04;

//多个线程同时操作一个对象
//购买火车票的例子

public class TestThread implements Runnable {

//    票数
    private  int ticakesnumms = 10;
    @Override
    public void run() {
        while(true){
            if (ticakesnumms<=0) {
                break;
            }
//            Thread.currentThread().getName()获取线程名称
//            tru-catch快捷键:ctrl+alt+t
//            模拟延时
            try {
                Thread.sleep(200);//延时
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticakesnumms--+"票");
        }
    }

    public static void main(String[] args) {
        TestThread testThread = new TestThread();

        new Thread(testThread,"小余").start();
        new Thread(testThread,"小唐").start();
        new Thread(testThread,"黄牛").start();

    }
}

案例:龟兔赛跑-Race

  1. 首先来个赛道距离,然后要离终点越来越近
  2. 判断比赛是否结束
  3. 打印出胜利者
  4. 龟兔赛跑开始
  5. 故事中是乌龟赢的,兔子需要睡觉,所以我们来模拟兔子睡觉
  6. 最后,乌龟赢得比赛
package Test;

//模拟龟兔赛跑
public class test1 implements Runnable {

    //胜利者
    private  static  String winner;

    @Override
    public void run() {
        for (int i = 0; i <= 100; i++) {

            //模拟兔子休息
            if (Thread.currentThread().getName().equals("兔子")&& i%90==0){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            //判断比赛是否结束
            boolean flag = gameOver(i);
            if (flag){
                break;//如果比赛结束就停止程序
            }
            System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
        }
    }

    //判断比赛是否结束
    private  boolean gameOver(int steps){
        //判断是否有胜利者
        if (winner!=null){//已经存在胜利者
            return true;
        }else{
            if (steps>=100){
            	//获取胜利者名字
                winner=Thread.currentThread().getName();
                System.out.println("winner is"+winner);
                return true;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        test1 test1 = new test1();
        new Thread(test1,"兔子").start();
        new Thread(test1,"乌龟").start();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值