第十七周Java实验作业
实验十七 线程同步控制
实验时间 2018-12-10
1、实验目的与要求
(1) 掌握线程同步的概念及实现技术;
多线程并发运行不确定性问题解决方案:引入线程同步机制,使得另一线程使用该方法,就只能等待。
在Java中解决多线程同步问题的方法有两种:
解决方案一:用ReentratLock保护代码块的基本结构如下:
myLock.lock();
try{
critical section
}
finally{
myLock.unlock();
}
有关锁对象和条件对象的关键要点:
锁用来保护代码片段,只要保证任何时刻只能有一个线程被保护的代码。
锁管理试图进入被保护代码段的进程。
锁可拥有一个或多个相关条件对象。
每个条件对象管理那些已经进入被保护的代码段但是还不能运行的线程。
解决方案二:synchronized关键字
synchronized关键字关键字作用:
某个类内方法用synchronized修饰后,该方法被称为同步方法;
只要某个线程正在访问同步方法,其他线程欲要访问同步方法就被阻塞,直至线程从同步方法返回前唤醒被阻塞线程,其他线程方法可进入同步方法。
一个线程在使用同步方法的中时,可能根据问题的需要,必须使用wait()方法使用本线程等待,暂时让出CPU的使用权,并允许其他线程使用这个同步方法。
线程如果用完同步方法,应当执行notifyAll()方法通知所有使用这个同步方法而处于等待的县城结束等待
多线程并发运行不确定性问题解决方案:引入线程同步机制,使得另一线程使用该方法,就只能等待。
在Java中解决多线程同步问题的方法有两种:
解决方案一:用ReentratLock保护代码块的基本结构如下:
myLock.lock();
try{
critical section
}
finally{
myLock.unlock();
}
有关锁对象和条件对象的关键要点:
锁用来保护代码片段,只要保证任何时刻只能有一个线程被保护的代码。
锁管理试图进入被保护代码段的进程。
锁可拥有一个或多个相关条件对象。
每个条件对象管理那些已经进入被保护的代码段但是还不能运行的线程。
解决方案二:synchronized关键字
synchronized关键字关键字作用:
某个类内方法用synchronized修饰后,该方法被称为同步方法;
只要某个线程正在访问同步方法,其他线程欲要访问同步方法就被阻塞,直至线程从同步方法返回前唤醒被阻塞线程,其他线程方法可进入同步方法。
一个线程在使用同步方法的中时,可能根据问题的需要,必须使用wait()方法使用本线程等待,暂时让出CPU的使用权,并允许其他线程使用这个同步方法。
线程如果用完同步方法,应当执行notifyAll()方法通知所有使用这个同步方法而处于等待的县城结束等待
2、实验内容和步骤
实验1:测试程序并进行代码注释。
测试程序1:
l 在Elipse环境下调试教材651页程序14-7,结合程序运行结果理解程序;
l 掌握利用锁对象和条件对象实现的多线程同步技术。
package synch; import java.util.*;
import java.util.concurrent.locks.*; /**
* 一种拥有许多银行帐户的银行,它使用锁来序列化访问。
* @version 1.30 2004-08-01
* @author Cay Horstmann
*/
public class Bank
{
private final double[] accounts;
private Lock bankLock;//锁对象
private Condition sufficientFunds; /**
*构建银行。
* @param 账户数量
* @param 每个账户的初始余额
*/
public Bank(int n, double initialBalance)
{
accounts = new double[n];
Arrays.fill(accounts, initialBalance);
bankLock = new ReentrantLock();
sufficientFunds = bankLock.newCondition();
} /**
* 把钱从一个账户转到另一个账户。
* @param 从账户转出
* @param 到账转到
* @param 转帐金额
*/
public void transfer(int from, int to, double amount) throws InterruptedException
{
bankLock.lock();//加锁
try
{
while (accounts[from] < amount)
sufficientFunds.await();//注释掉之后产生死锁现象
System.out.print(Thread.currentThread());
accounts[from] -= amount;
System.out.printf(" %10.2f from %d to %d", amount, from, to);
accounts[to] += amount;
System.out.printf(" Total Balance: %10.2f%n", getTotalBalance());
sufficientFunds.signalAll();//注释掉之后产生死锁现象
}
finally
{
bankLock.unlock();
}
} /**
*获取所有帐户余额的总和。
* @return 总平衡
*/
public double getTotalBalance()
{
bankLock.lock();//加锁
try
{
double sum = 0; for (double a : accounts)
sum += a; return sum;
}
finally
{
bankLock.unlock();//解锁
}
} /**
* 获取银行中的帐户编号。
* @return 账户数量
*/
public int size()
{
return accounts.length;
}
}
package synch;
/**
* 这个程序展示了多线程如何安全地访问数据结构。
* @version 1.31 2015-06-21
* @author Cay Horstmann
*/
public class SynchBankTest
{
public static final int NACCOUNTS = 100;
public static final double INITIAL_BALANCE = 1000;
public static final double MAX_AMOUNT = 1000;
public static final int DELAY = 10; public static void main(String[] args)
{
Bank bank = new Bank(NACCOUNTS, INITIAL_BALANCE);
for (int i = 0; i < NACCOUNTS; i++)
{
int fromAccount = i;
Runnable r = () -> {
try
{
while (true)
{
int toAccount = (int) (bank.size() * Math.random());
double amount = MAX_AMOUNT * Math.random();
bank.transfer(fromAccount, toAccount, amount);
Thread.sleep((int) (DELAY * Math.random()));
}
}
catch (InterruptedException e)
{
}
};
Thread t = new Thread(r);
t.start();
}
}
}
运行结果:

测试程序2:
l 在Elipse环境下调试教材655页程序14-8,结合程序运行结果理解程序;
l 掌握synchronized在多线程同步中的应用。
package synch2; /**
* 这个程序展示了多线程如何安全地访问一个数据结构,使用同步方法。
* @version 1.31 2015-06-21
* @author Cay Horstmann
*/
public class SynchBankTest2
{
public static final int NACCOUNTS = 100;
public static final double INITIAL_BALANCE = 1000;
public static final double MAX_AMOUNT = 1000;
public static final int DELAY = 10; public static void main(String[] args)
{
Bank bank = new Bank(NACCOUNTS, INITIAL_BALANCE);
for (int i = 0; i < NACCOUNTS; i++)
{
int fromAccount = i;
Runnable r = () -> {
try
{
while (true)
{
int toAccount = (int) (bank.size() * Math.random());
double amount = MAX_AMOUNT * Math.random();
bank.transfer(fromAccount, toAccount, amount);
Thread.sleep((int) (DELAY * Math.random()));
}
}
catch (InterruptedException e)
{
}
};
Thread t = new Thread(r);
t.start();
}
}
}
package synch2; import java.util.*; /**
* 使用同步原语的具有多个银行帐户的银行
* @version 1.30 2004-08-01
* @author Cay Horstmann
*/
public class Bank
{
private final double[] accounts; /**
* 构建了银行。
* @param 账户数量
* @param 每个账户的初始余额
*/
public Bank(int n, double initialBalance)
{
accounts = new double[n];
Arrays.fill(accounts, initialBalance);
} /**
* 把钱从一个账户转到另一个账户。
* @param 从账户转出
* @param 到账转到
* @param 转帐金额
*/
public synchronized void transfer(int from, int to, double amount) throws InterruptedException
{
while (accounts[from] < amount)
wait();//Object类
System.out.print(Thread.currentThread());
accounts[from] -= amount;
System.out.printf(" %10.2f from %d to %d", amount, from, to);
accounts[to] += amount;
System.out.printf(" Total Balance: %10.2f%n", getTotalBalance());
notifyAll();
}
/**
*获取所有帐户余额的总和。
* @return 总平衡
*/
public synchronized double getTotalBalance()
{
double sum = 0; for (double a : accounts)
sum += a; return sum;
} /**
* 获取银行中的帐户编号。
* @return 账户数量
*/
public int size()
{
return accounts.length;
}
}
运行结果:

测试程序3:
l 在Elipse环境下运行以下程序,结合程序运行结果分析程序存在问题;
l 尝试解决程序中存在问题。
|
class Cbank { private static int s=2000; public static void sub(int m) { int temp=s; temp=temp-m; try { Thread.sleep((int)(1000*Math.random())); } catch (InterruptedException e) { } s=temp; System.out.println("s="+s); } } class Customer extends Thread { public void run() { for( int i=1; i<=4; i++) Cbank.sub(100); } } public class Thread3 { public static void main(String args[]) { Customer customer1 = new Customer(); Customer customer2 = new Customer(); customer1.start(); customer2.start(); } } |
运行结果:

修正后:
class Cbank
{
private static int s=2000;
public synchronized static void sub(int m)
{
int temp=s;
temp=temp-m;
try {
Thread.sleep((int)(1000*Math.random()));
}
catch (InterruptedException e) { }
s=temp;
System.out.println("s="+s);
}
}
class Customer extends Thread
{
public void run()
{
for( int i=1; i<=4; i++)
Cbank.sub(100);
}
}
public class Thread3
{
public static void main(String args[])
{
Customer customer1 = new Customer();
Customer customer2 = new Customer();
customer1.start();
customer2.start();
}
}
运行结果:

实验2 编程练习
利用多线程及同步方法,编写一个程序模拟火车票售票系统,共3个窗口,卖10张票,程序输出结果类似(程序输出不唯一,可以是其他类似结果)。
Thread-0窗口售:第1张票
Thread-0窗口售:第2张票
Thread-1窗口售:第3张票
Thread-2窗口售:第4张票
Thread-2窗口售:第5张票
Thread-1窗口售:第6张票
Thread-0窗口售:第7张票
Thread-2窗口售:第8张票
Thread-1窗口售:第9张票
Thread-0窗口售:第10张票
package 小陈;
public class thread {
public static void main(String[] args) {
Ticket ticket = new Ticket();
Thread t1 = new Thread(ticket);
Thread t2 = new Thread(ticket);
Thread t3 = new Thread(ticket);
t1.start();
t2.start();
t3.start();
}
}
class Ticket implements Runnable{
int t = 1;
boolean flag = true;
public void run() {
while(flag) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (this) {
if(t<=10) {
System.out.println(Thread.currentThread().getName()+"窗口售:"+"第"+t+"张票");
t++;
}else {
flag = false;
}
}
}
}
}
运行结果:

个人总结:本周主要学了线程的同步控制的相关知识,同时在实验课上学习了一些快速构造代码的快捷键,对编程的帮助比较大,个人觉得还是比较有收获的,还要继续学习。
第十七周Java实验作业的更多相关文章
- 第十八周java实验作业
实验十八 总复习 实验时间 2018-12-30 1.实验目的与要求 (1) 综合掌握java基本程序结构: (2) 综合掌握java面向对象程序设计特点: (3) 综合掌握java GUI 程序设 ...
- 第十五周java实验作业
实验十五 GUI编程练习与应用程序部署 实验时间 2018-12-6 1.实验目的与要求 (1) 掌握Java应用程序的打包操作: Java程序的打包,程序编译完成后,程序员将.class文件压缩打 ...
- 第十六周Java实验作业
实验十六 线程技术 实验时间 2017-12-8 1.实验目的与要求 (1) 掌握线程概念: 多线程是进程执行过程中产生的多条执行线索,线程是比进程执行更小的单位. 线程不能独立存在,必须存在于进程 ...
- 第十二周java实验作业
实验十二 图形程序设计 实验时间 2018-11-14 1.实验目的与要求 (1) 掌握Java GUI中框架创建及属性设置中常用类的API: Java的集合框架实现了对各种数据结构的封装. jav ...
- 第十一周Java实验作业
实验十一 集合 实验时间 2018-11-8 1.实验目的与要求 (1) 掌握Vetor.Stack.Hashtable三个类的用途及常用API: Vector类类似长度可变的数组,其中只能存放对 ...
- 第十周Java实验作业
实验十 泛型程序设计技术 实验时间 2018-11-1 1.实验目的与要求 (1) 理解泛型概念: 泛型:也称参数化类型,就是在定义类,接口和方法时,通过类型参数只是将要处理的类型对象.(如Arra ...
- 第九周Java实验作业
实验九 异常.断言与日志 实验时间 2018-10-25 1.实验目的与要求 (1) 掌握java异常处理技术: Java的异常处理机制可以控制程序从错误产生的位置转移到能够进行错误处理的位置. Ja ...
- 第八周Java实验作业
实验六 接口的定义与使用 实验时间 2018-10-18 1.实验目的与要求 (1) 掌握接口定义方法: 声明: public interface 接口名 {...} 接口体中包含常量定义和方法定义 ...
- 第七周java实验作业
实验七 继承附加实验实验时间 2018-10-11 1.实验目的与要求 (1)进一步理解4个成员访问权限修饰符的用途: Public 该类或非该类均可访问 Private 只有该类可以访问 Pro ...
随机推荐
- python os.path 模块常用方法
代码: import os apath = os.path.abspath(__file__) # 绝对路径 dirname = os.path.dirname(apath) basename = o ...
- CC03 iOS推送机制浅析
• ios推送机制 可以通俗的把APNS理解为iOS系统为每个app提供的长连接通道 苹果限制了每个app在后台存活的时间,最重要的目的是为了省电,其次优化内存这些.如果彻彻底底的将app杀死了,服务 ...
- 机器学习 —— 数据预处理
对于学习机器学习算法来说,肯定会涉及到数据的处理,因此一开始,对数据的预处理进行学习 对于数据的预处理,大概有如下几步: 步骤1 -- 导入所需库 导入处理数据所需要的python库,有如下两个库是非 ...
- runR
Linux下使用R 运行linux下的R脚本 编写R文件 新建后缀名为R的文件 写入R程序 在脚本首行加入 1 运行R文件 这里有两种方式 大专栏 runR进入R的环境">进入R的环 ...
- 当鼠标hover的时候,使用tip将overflow:hidden隐藏的文字显示完全
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 极验验证码破解之selenium
这一篇写完很久了,因为识别率一直很低,没办法拿出来见大家,所以一直隐藏着,今天终于可以拿出来见见阳光了. 哈喽,大家好,我是星星在线,我又来了,今天给大家带来的是极验验证码的selenium破解之法, ...
- sublime 安装Anaconda插件 配置python开发环境
我的sublime 3 python 3.6.6 安装Anaconda插件 由于Anaconda插件本身无法知道Python安装的路径,所以需要设置Python主程序的实际位置.选择Settings ...
- Web Scraper 高级用法——抓取属性信息 | 简易数据分析 16
这是简易数据分析系列的第 16 篇文章. 这期课程我们讲一个用的较少的 Web Scraper 功能--抓取属性信息. 网页在展示信息的时候,除了我们看到的内容,其实还有很多隐藏的信息.我们拿豆瓣电影 ...
- sql03
1.约束 约束详解 ->约束的目的:保证数据的完整性. not null ->默认值约束.可空约束.主键约束.外键约束.唯一键约束.检查约束 1) 用sql语句为表添加新的字段 2) 为字 ...
- a标签嵌套href默认行为与子元素click事件存在影响
2018-08-07 Question about work 开发过程中遇到问题,简单写个demo 运行环境为Chrome 68 描述一下这个问题,当<a>标签内部存在嵌套时, 父元素&l ...