多线程尝试(一)

原创 2018年04月14日 23:09:37

今天了解多线程的过程中,随手写了一个银行存钱的Demo,对于部分业务需要用到同步机制。

先看代码:

这是模拟银行账户的抽象类:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author:KrisYu
 * @Description:银行账户
 */
public class Account {

    //账户余额
    private Double balance = 0d;

    //存钱
    public void saveMoney(Double money) {
        Double newMoney = balance + money;
        //模拟存钱需要时间
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        balance = newMoney;
    }

    //查看余额
    public Double getBalence() {
        System.out.println("还剩余额:" + balance + "元");
        return balance;
    }
}

这是把存钱的操作单独抽成一个类,用于线程操作

/**
 * @Author:KrisYu
 * @Description:存钱线程
 */
public class AddMoneyThread implements Runnable {
    private Account account;
    private Double money;

    public AddMoneyThread(Account account,Double money){
        this.account = account;
        this.money = money;
    }

    public void run() {
            account.saveMoney(money);
    }
}

最后是操作类,简历线程池,用于实现100次的线程操作

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Author:KrisYu
 * @Description:存钱线程
 */
public class AccountTest {

    public static void main(String[] args) {
        Account yuAccount = new Account();
        Double money = 1d;
        AddMoneyThread addMoneyThread = new AddMoneyThread(yuAccount, money);
        ExecutorService executorService = Executors.newFixedThreadPool(100);

        for (int i = 0; i < 100; i++) {
            executorService.execute(new AddMoneyThread(yuAccount, money));
        }
        executorService.shutdown();
        //确保线程关闭完全,不然的话是死循环
        while (!executorService.isTerminated()) {
        }
        yuAccount.getBalence();

    }
}

执行100词存钱,每次存一元,但是惊奇的发现 打印的结果往往只有个位数甚至1元,让我们进入思考,多个线程并发运行,大多数线程都是取到了0余额然后对其加1元所以结果不在预料之内。要改正只能保证每一次存钱操作同步进行,我在这里提供三个思路

一:

直接在存钱操作上加上synchronized关键字保证saveMoney()方法上锁,同一时刻最多有一个线程来执行这个方法。

//存钱
public synchronized void saveMoney(Double money) {
    Double newMoney = balance + money;
    //模拟存钱需要时间
    try {
        Thread.sleep(10);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    balance = newMoney;
}

二:直接再重写的run方法给Account对象上锁,保证对这个对象最多有一个线程来进入对象修改信息

public void run() {
    synchronized (account) {
        account.saveMoney(money);
    }
}

三:在saveMoney()方法中上重入锁把存钱相关代码上锁,并在执行完成后解锁

//重入锁
private Lock accountLock = new ReentrantLock();

//存钱
public synchronized void saveMoney(Double money) {
    accountLock.lock();
    try {
        Double newMoney = balance + money;
        //模拟存钱需要时间
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        balance = newMoney;
    } finally {
        accountLock.unlock();
    }
}

好,今天写到这里,欢迎大家在评论区回答你最喜欢的同步方式,并写上原因。

参考文献:骆昊的博客




廖雪峰python学习笔记15.正则表达式入门

# -*- coding:utf-8 -*- #正则表达式是一种用来匹配字符串的强有力的武器 #用\d可以匹配一个数字,\w可以匹配一个字母或数字 """ '00\d'可以匹配'007',但无法匹...
  • thinkerleo1997
  • thinkerleo1997
  • 2016-07-14 10:53:45
  • 548

正则表达式学习小结

字符串是编程时涉及到的最多的一种数据结构,对字符串进行操作的需求几乎无处不在。比如判断一个字符串是否是合法的Email地址,虽然可以编程提取@前后的子串,再分别判断是否是单词和域名,但这样做不但麻烦,...
  • wolongdede
  • wolongdede
  • 2014-09-05 11:26:50
  • 402

多线程尝试

先贴代码 package com.mult.test; public class MyThread { public static void main(String[] args) thr...
  • Sgr_pippo
  • Sgr_pippo
  • 2015-02-25 14:30:30
  • 255

多线程并发同一个表问题

现有数据库开发过程中对事务的控制、事务锁、行锁、表锁的发现缺乏必要的方法和手段,通过以下手段可以丰富我们处理开发过程中处理锁问题的方法。 For Update和For Update of使用户能够锁...
  • aalansehaiyang52
  • aalansehaiyang52
  • 2011-09-12 18:48:16
  • 1377

redis复习(二):高级命令,主从复制,哨兵模式

一:redis高级命令 keys *:查看所有key(可以模糊匹配) exists:是否存在指定的key expire:设置某个key的过期时间,ttl查看过期剩余时间 persist:取消某...
  • Lee_Ho_
  • Lee_Ho_
  • 2017-10-04 15:58:17
  • 101

websphere WTRN0063E: 非法尝试与现有两阶段资源一起落实一阶段资源

在百度空间看到一位同学遇到的问题: 在一个事务中同时使用了XA的数据源和非XA数据源,因此报错,通过统一使用XA的数据源解决了问题  WTRN0063E: 非法尝试与现有两阶段资源一起落实一阶段资源...
  • lisa_ljy
  • lisa_ljy
  • 2011-02-22 15:57:00
  • 2420

黑马程序员——管道流:PipedInputStream和PipedOutputStream与线程的结合运用

位于java.io中的PipedInputStream和PipedOutputStream是java的两个常用的读写管导流,平时一般读数据,我们都是先把一些数据读取放在一个数组中,再对数组进行操作,写...
  • zp357252539
  • zp357252539
  • 2014-12-02 23:26:23
  • 736

python正则表达式匹配邮箱地址是否合法

题目: 1)请尝试写一个验证Email地址的正则表达式。版本一应该可以验证出类似的Email: someone@gmail.com bill.gates@microsoft.com 2)版本二...
  • qq_37591656
  • qq_37591656
  • 2017-11-21 13:15:59
  • 180

黑马程序员_多线程与并发

在过去单CPU时代,单任务在一个时间点只能执行单一程序。之后发展到多任务阶段,计算机能在同一时间点并行执行多任务或多进程。虽然并不是真正意义上的“同一时间点”,而是多个任务或进程共享一个CPU,并交由...
  • hey_2
  • hey_2
  • 2014-08-06 10:17:41
  • 317

用多线程加速快排(方式一)

运行环境: 硬件条件:电脑必须是双核及以上,这样两个线程才能真正分布到两个处理器上运行。 开发环境:VC6.0 经典的快排如下: #include #include #include #inclu...
  • WoBenFengYa
  • WoBenFengYa
  • 2013-10-05 21:12:21
  • 1091
收藏助手
不良信息举报
您举报文章:多线程尝试(一)
举报原因:
原因补充:

(最多只允许输入30个字)