Java基础之线程——管理线程同步方法(BankOperation2)
控制台程序。
当两个或多个线程共享同一资源时,例如文件或内存块,就需要采取措施,确保其中的一个线程不会修改另一个线程正在使用的资源。当其中的一个线程更新文件中的某个记录,同时另一个线程正在检索这个记录,就会出现灾难性的结果。管理这种情形的一种方式是对涉及的线程使用同步机制。
同步的目标是当多个线程希望访问同一资源时,确保在任意时刻只有一个线程可以访问。使用同步机制可以通过两种方式管理线程的执行:
1、可以在方法级别管理代码,这涉及方法的同步。
2、可以在块级别管理代码,这使用块的同步。
同步方法可以使任意类中方法的子集(或者所有的方法)都是互斥的,在任意时刻都只能执行其中的一个方法。使用synchronized关键字声明类中的方法,就可以把它们设置为互斥的。
// Define the bank
public class Bank {
// Perform a transaction
synchronized public void doTransaction(Transaction transaction) {
int balance = transaction.getAccount().getBalance(); // Get current balance
switch(transaction.getTransactionType()) {
case CREDIT:
// Credits require a lot of checks...
try {
Thread.sleep(100);
} catch(InterruptedException e) {
System.out.println(e);
}
balance += transaction.getAmount(); // Increment the balance
break;
case DEBIT:
// Debits require even more checks...
try {
Thread.sleep(150);
} catch(InterruptedException e) {
System.out.println(e);
}
balance -= transaction.getAmount(); // Decrement the balance
break;
default: // We should never get here
System.out.println("Invalid transaction");
System.exit(1);
}
transaction.getAccount().setBalance(balance); // Restore the account balance
}
}
// Defines a customer account
public class Account {
// Constructor
public Account(int accountNumber, int balance) {
this.accountNumber = accountNumber; // Set the account number
this.balance = balance; // Set the initial balance
} // Return the current balance
public int getBalance() {
return balance;
} // Set the current balance
public void setBalance(int balance) {
this.balance = balance;
} public int getAccountNumber() {
return accountNumber;
} @Override
public String toString() {
return "A/C No. " + accountNumber + " : $" + balance;
} private int balance; // The current account balance
private int accountNumber; // Identifies this account
}
// Bank account transaction types
public enum TransactionType {DEBIT, CREDIT }
public class Clerk implements Runnable {
// Constructor
public Clerk(Bank theBank) {
this.theBank = theBank; // Who the clerk works for
inTray = null; // No transaction initially
}
// Receive a transaction
public void doTransaction(Transaction transaction) {
inTray = transaction;
}
// The working clerk...
public void run() {
while(true) { // Non-stop work...
while(inTray == null) { // No transaction waiting?
try {
Thread.sleep(150); // Then take a break...
} catch(InterruptedException e) {
System.out.println(e);
}
}
theBank.doTransaction(inTray);
inTray = null; // In-tray is empty
}
}
// Busy check
public boolean isBusy() {
return inTray != null; // A full in-tray means busy!
}
private Bank theBank; // The employer - an electronic marvel
private Transaction inTray; // The in-tray holding a transaction
}
public class Transaction {
// Constructor
public Transaction(Account account, TransactionType type, int amount) {
this.account = account;
this.type = type;
this.amount = amount;
}
public Account getAccount() {
return account;
}
public TransactionType getTransactionType() {
return type;
}
public int getAmount() {
return amount;
}
@Override
public String toString() {
return type + " A//C: " + account + ": $" + amount;
}
private Account account;
private int amount;
private TransactionType type;
}
import java.util.Random;
public class BankOperation2 {
public static void main(String[] args) {
int initialBalance = 500; // The initial account balance
int totalCredits = 0; // Total credits on the account
int totalDebits =0; // Total debits on the account
int transactionCount = 20; // Number of debits and credits
// Create the account, the bank, and the clerks...
Bank theBank = new Bank(); // Create a bank
Clerk clerk1 = new Clerk(theBank); // Create the first clerk
Clerk clerk2 = new Clerk(theBank); // Create the second clerk
Account account = new Account(1, initialBalance); // Create an account
// Create the threads for the clerks as daemon, and start them off
Thread clerk1Thread = new Thread(clerk1);
Thread clerk2Thread = new Thread(clerk2);
clerk1Thread.setDaemon(true); // Set first as daemon
clerk2Thread.setDaemon(true); // Set second as daemon
clerk1Thread.start(); // Start the first
clerk2Thread.start(); // Start the second
// Generate transactions of each type and pass to the clerks
Random rand = new Random(); // Random number generator
Transaction transaction; // Stores a transaction
int amount = 0; // stores an amount of money
for(int i = 1 ; i <= transactionCount ; ++i) {
amount = 50 + rand.nextInt(26); // Generate amount of $50 to $75
transaction = new Transaction(account, // Account
TransactionType.CREDIT, // Credit transaction
amount); // of amount
totalCredits += amount; // Keep total credit tally
// Wait until the first clerk is free
while(clerk1.isBusy()) {
try {
Thread.sleep(25); // Busy so try later
} catch(InterruptedException e) {
System.out.println(e);
}
}
clerk1.doTransaction(transaction); // Now do the credit
amount = 30 + rand.nextInt(31); // Generate amount of $30 to $60
transaction = new Transaction(account, // Account
TransactionType.DEBIT, // Debit transaction
amount); // of amount
totalDebits += amount; // Keep total debit tally
// Wait until the second clerk is free
while(clerk2.isBusy()) {
try {
Thread.sleep(25); // Busy so try later
} catch(InterruptedException e) {
System.out.println(e);
}
}
clerk2.doTransaction(transaction); // Now do the debit
}
// Wait until both clerks are done
while(clerk1.isBusy() || clerk2.isBusy()) {
try {
Thread.sleep(25);
} catch(InterruptedException e) {
System.out.println(e);
}
}
// Now output the results
System.out.println(
"Original balance : $" + initialBalance+"\n" +
"Total credits : $" + totalCredits+"\n" +
"Total debits : $" + totalDebits+"\n" +
"Final balance : $" + account.getBalance() + "\n" +
"Should be : $" + (initialBalance + totalCredits - totalDebits));
}
}
把处理账户的方法声明为synchronized,在其中一个职员对账户调用方法时,禁止另一个职员也调用同一个方法。
目前存在的问题是:银行的效率非常低,当其中一个职员在处理事物时,另一个职员却在闲着。
Java基础之线程——管理线程同步方法(BankOperation2)的更多相关文章
- java笔记--用ThreadLocal管理线程,Callable<V>接口实现有返回值的线程
用ThreadLocal管理线程,Callable<V>接口实现有返回值的线程 ThreadLocal在我的笔记"关于线程同步"的第5种方式里面有介绍,这里就不多说了. ...
- JAVA基础知识之多线程——线程池
线程池概念 操作系统或者JVM创建一个线程以及销毁一个线程都需要消耗CPU资源,如果创建或者销毁线程的消耗源远远小于执行一个线程的消耗,则可以忽略不计,但是基本相等或者大于执行线程的消耗,而且需要创建 ...
- JAVA基础知识之多线程——线程同步
线程安全问题 多个线程同时访问同一资源的时候有可能会出现信息不一致的情况,这是线程安全问题,下面是一个例子, Account.class , 定义一个Account模型 package threads ...
- Java基础之多线程篇(线程创建与终止、互斥、通信、本地变量)
线程创建与终止 线程创建 Thread类与Runnable接口的关系 public interface Runnable { public abstract void run(); } public ...
- Java基础学习——多线程之线程池
1.线程池介绍 线程池是一种线程使用模式.线程由于具有空闲(eg:等待返回值)和繁忙这种不同状态,当数量过多时其创建.销毁.调度等都会带来开销.线程池维护了多个线程,当分配可并发执行的任务时, ...
- JAVA基础知识之多线程——线程组和未处理异常
线程组 Java中的ThreadGroup类表示线程组,在创建新线程时,可以通过构造函数Thread(group...)来指定线程组. 线程组具有以下特征 如果没有显式指定线程组,则新线程属于默认线程 ...
- 黑马程序员——JAVA基础之多线程的线程间通讯等
------- android培训.java培训.期待与您交流! ---------- 线程间通讯: 其实就是多个线程在操作同一个资源,但是动作不同. wait(); 在其他线程调用此对象的notif ...
- Java基础(四)线程快速了解
开始整理线程之前,之前有个命令忘记整理了,先整理一下jar命令的使用 Jar包 其实可以理解是java的压缩包方便使用,只要在classpath设置jar路径即可数据库驱动,ssh框架等都是以jar包 ...
- java基础(26):Thread、线程创建、线程池
1. 多线程 1.1 多线程介绍 学习多线程之前,我们先要了解几个关于多线程有关的概念. 进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并 ...
随机推荐
- java build path->source folder分析
1.build path下的source folde,指的是项目存放源码的位置,即存放Java代码的位置!!! 如果将一个文件夹设为java build path里的source folder下,则这 ...
- VS常见错误
error C2572: “****”: 重定义默认参数 : 参数 默认参数只需在声明原型时使用,定义的时候就不需要. error C2572
- 来到这里,我放弃了多少- UI基础-疯狂猜图,我们都疯狂了-
小问题也要问 学习最重要的是 自律 我昨天晚上3点睡的, 这两天一点也没睡 0.99*0.99 每天差一点 日积月累就很多了 关键字,在字典里查一下,在类里面查查 瑞详博客下载器 跑步后精神多了,白 ...
- Structured Streaming Programming Guide
https://spark.apache.org/docs/latest/structured-streaming-programming-guide.html http://www.slidesha ...
- Flink - Generating Timestamps / Watermarks
https://ci.apache.org/projects/flink/flink-docs-release-1.0/apis/streaming/event_timestamps_watermar ...
- nginx生产配置
user www www; worker_processes 8; error_log /data/logs/nginx_error.log crit; pid /usr/local/webserve ...
- android ArrayAdapter 如何动态更改数据
在android开发中ListView是比较常用的组件,它以列表的形式展示具体内容,并且能够根据数据的长度自适应显示,使用adpater与listview捆绑后,有时希望在程序使用过程中能动态的更改l ...
- 【转】四元数(Quaternion)和旋转
四元数介绍 旋转,应该是三种坐标变换--缩放.旋转和平移,中最复杂的一种了.大家应该都听过,有一种旋转的表示方法叫四元数.按照我们的习惯,我们更加熟悉的是另外两种旋转的表示方法--矩阵旋转和欧拉旋转. ...
- J2msi 自己制作的把exe打成安装包简易GUI程序(第二版 带DLL注册)
J2msi 自己制作的把exe打成安装包简易GUI程序(第二版 带DLL注册) 之前那一版本(http://www.cnblogs.com/rojas/p/4794684.html)没考虑 DLL 注 ...
- Difference Search Path
1.Framework Search Path where to search frameworks (.framework bundles) in addition to sys ...