在说之前先普及一下线程是什么?
线程:说白了就是一个任务片段
进程:是一个具有独立功能的程序关于某个数据集合的一次运行活动,一个进程有一个或者多个线程
线程与进程的本质区别就是有么有数据共享空间,线程之间可以共享数据,进程不可以
下面进入主题:线程间的同步
由于现在业务流程增加,业务节点也增加,使用业务的人员也同时增加,这个时候就不可避免的出现并发问题,多个线程同时访问操作某一个数据单元
我们以银行转账为例说明,下面先上代码:
建立一个银行的类,里面主要包括三个方法,一个是转账,一个是得到现有银行存款总数,一个是得到现在存户数量
public class Bank {
private final double[] accounts;
public Bank(int n, double initialBalance) {
accounts = new double[n];
for (int i = 0; i < accounts.length; i++) {
accounts[i] = initialBalance;
}
}
public void transfer(int from, int to, double amount) {
if (accounts[from] < amount) {
return;
}
System.out.println(Thread.currentThread());
accounts[from] -= amount;
System.out.printf("%f from %d to %d ", amount, from, to);
accounts[to] += amount;
System.out.println("total:" + getTotalBalance());
}
public double getTotalBalance() {
double sum = 0d;
for (int i = 0; i < accounts.length; i++) {
sum += accounts[i];
}
return sum;
}
public int getAccountSize() {
return accounts.length;
}
}
下面是转账类,因为需要并发操作,所以实现Runnable接口
public class TransferRunnable implements Runnable {
private Bank bank;
private int fromAccount = 0;
private double maxAmount = 0;
public TransferRunnable(Bank b, int fromAccount, double maxAmount) {
this.bank = b;
this.fromAccount = fromAccount;
this.maxAmount = maxAmount;
}
@Override
public void run() {
double amount = maxAmount * Math.random();
int toAccount = (int) ((int) bank.getAccountSize() * Math.random());
bank.transfer(fromAccount, toAccount, amount);
try {
Thread.sleep((long) (100L * Math.random()));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
下面是测试类:
public class Test {
public static void main(String[] args) {
Bank bank = new Bank(100, 1000);
for (int i = 0; i < 3; i++) {
TransferRunnable transferRunnable = new TransferRunnable(bank, i,
1000);
Thread thread = new Thread(transferRunnable);
thread.start();
}
}
}
输出结果:
Thread[Thread-0,5,main]
Thread[Thread-2,5,main]
Thread[Thread-1,5,main]
430.796266 from 0 to 75
714.274395 from 1 to 88
849.880218 from 2 to 33
total:98435.8453871716
total:99150.11978192833
total:100000.0
我们看上面的结果,特别是最后三行的total总数,发现,第一第二次转账后,总数不对了,仔细观察打印结果,由于并行执行任务,而且中间由于是由cup分配执行顺序,所以我们看到的结果并没有完全按照我们的方法所实现的那样输出出来
由于出现这样的问题,我们引入“锁”的概念,由于这里面是浅析,就不针对锁详细说明,下面我们在bank类里面的转账方法上面加上最简单最常用的锁synchronized,看看结果是怎样:
public class Bank {
private final double[] accounts;
public Bank(int n, double initialBalance) {
accounts = new double[n];
for (int i = 0; i < accounts.length; i++) {
accounts[i] = initialBalance;
}
}
//加了锁
public synchronized void transfer(int from, int to, double amount) {
if (accounts[from] < amount) {
return;
}
System.out.println(Thread.currentThread());
accounts[from] -= amount;
System.out.printf("%f from %d to %d ", amount, from, to);
accounts[to] += amount;
System.out.println("total:" + getTotalBalance());
}
public double getTotalBalance() {
double sum = 0d;
for (int i = 0; i < accounts.length; i++) {
sum += accounts[i];
}
return sum;
}
public int getAccountSize() {
return accounts.length;
}
}
输出结果:
Thread[Thread-0,5,main]
187.754955 from 0 to 50 total:100000.0
Thread[Thread-1,5,main]
282.138799 from 1 to 90 total:100000.0
Thread[Thread-2,5,main]
217.089515 from 2 to 86 total:100000.00000000001
上面的输出结果基本一致,最后一个结果出现小数问题,主要是由于我数据精度的问题,后续可以通过其他设置来避免。
程序里面由于出现了锁,所以在性能上面不可避免的出现下降,特别是在一些大型程序里面,所以这里面需要根据实际业务所需,把锁的范围锁到比较小的范围,使得性能不会大幅度的下降。
最后我们把上面的东西总结出一个图
版权声明:本文为博主原创文章,未经博主允许不得转载。
分享到:
相关推荐
完整版Java全套入门培训课件 Java基础 05-多线程(共12页).rar
基于java的开发源码-多线程程序死锁检查 JCarder.zip 基于java的开发源码-多线程程序死锁检查 JCarder.zip 基于java的开发源码-多线程程序死锁检查 JCarder.zip 基于java的开发源码-多线程程序死锁检查 JCarder.zip ...
多线程注意:wait()方法的调用要有判定条件常用 while () obj.wait(timeout, nanos); ... // Perform action appropriate to condition } synchronized会影响共享数据,但对其他语句的执行不会有规律了!
Java多线程--多线程相关概念
Java全套入门培训课件 Java基础 05-多线程(共12页).pptx Java全套入门培训课件 Java基础 06-集合(共24页).pptx Java全套入门培训课件 Java基础 07-IO(共29页).pptx Java全套入门培训课件 Java基础 08-GUI图形...
4JAVA编程高级-多线程编程
Java多线程--多线程知识点总结和企业真题
【完整课程列表】 Java基础[01-Java概述].pdf Java基础[02-Java基础语法1].pdf ...Java基础[05-多线程].pdf Java基础[06-集合].pdf Java基础[07-IO].pdf Java基础[08-GUI].pdf Java基础[09-网络编程].pdf
java基础--11.多线程-1
多线程 进程 线程(例:FlashGet) 多线程存在的意义。 线程的创建方式 多线程的特性
Java多线程--等待所有子线程执行完的五种方法 Java多线程--等待所有子线程执行完的五种方法 Java多线程--等待所有子线程执行完的五种方法 Java多线程--等待所有子线程执行完的五种方法 Java多线程--等待所有子线程...
java基础--11.多线程
模拟实现多线程处理银行的实时转账交易,代码完整,可以完美运行~
vc++ 多线程教程---线程通信--利用事件对象,线程同步--使用信号量,线程同步--使用互斥量,线程同步--使用临界区
01大数据面试复习----Java基础---集合类、多线程、JVM.zip
Java多线程--线程的安全问题与线程的同步机制介绍
Java基础[05-多线程]
【完整课程列表】 ... 完整版精品java课件 ...完整版精品java课件 Java基础入门教程 Java程序设计 第13章 多线程(共24页).ppt 完整版精品java课件 Java基础入门教程 Java程序设计 第14章 socket网络编程(共24页).ppt
JAVA-多线程 所有文件