201771010126 王燕《面向对象程序设计(Java)》第十七周学习总结
实验十七 线程同步控制
实验时间 2018-12-10
1、实验目的与要求
(1) 掌握线程同步的概念及实现技术;
多线程并发运行不确定性问题解决方案: 多线程并发运行不确定性问题解决方案: 多线程并发运行不确定性问题解决方案: 多线程并发运行不确定性问题解决方案: 多线程并发运行不确定性问题解决方案: 多线程并发运行不确定性问题解决方案: 多线程并发运行不确定性问题解决方案: 多线程并发运行不确定性问题解决方案: 多线程并发运行不确定性问题解决方案: 多线程并发运行不确定性问题解决方案: 多线程并发运行不确定性问题解决方案: 多线程并发运行不确定性问题解决方案: 多线程并发运行不确定性问题解决方案: 多线程并发运行不确定性问题解决方案: 多线程并发运行不确定性问题解决方案: 多线程并发运行不确定性问题解决方案: 多线程并发运行不确定性问题解决方案: 多线程并发运行不确定性问题解决方案: 引入线 引入线 引入线 程同步机制 程同步机制 程同步机制 程同步机制 程同步机制 ,使得另一线程要用该方法 使得另一线程要用该方法 使得另一线程要用该方法 使得另一线程要用该方法 使得另一线程要用该方法 使得另一线程要用该方法 使得另一线程要用该方法 使得另一线程要用该方法 使得另一线程要用该方法 使得另一线程要用该方法 使得另一线程要用该方法 使得另一线程要用该方法 ,就只 能等待 。
在Java 中解决多线程同步问题 的方法有两种: 的方法有两种: 的方法有两种: 的方法有两种: 的方法有两种: 的方法有两种: 的方法有两种:
-Java SE 5.0中引入 ReentrantLock ReentrantLock ReentrantLockReentrantLock ReentrantLock类(P 648648648页)。
-在共享内存的类方法前加 在共享内存的类方法前加 在共享内存的类方法前加 在共享内存的类方法前加 在共享内存的类方法前加 在共享内存的类方法前加 在共享内存的类方法前加 在共享内存的类方法前加 在共享内存的类方法前加 在共享内存的类方法前加 在共享内存的类方法前加 synchronizedsynchronizedsynchronized synchronized synchronized synchronizedsynchronized修饰符 修饰符 修饰符 。
解决方案一:锁对象 与条件解决方案一:锁对象与条件
用ReentrantLock 保护代码块的基本结构如下:
myLock.lock myLock.lock myLock.lockmyLock.lock ();
try { try {try {try {
critical section critical section critical section critical section critical section }
finally{ finally{ finally{
myLock.unlock myLock.unlock myLock.unlockmyLock.unlock myLock.unlock (); (); (); (); }
有关锁对象和条件的键要点 有关锁对象和条件的键要点 :
锁用来保护代码片段 用来保护代码片段 用来保护代码片段 用来保护代码片段 用来保护代码片段 用来保护代码片段 用来保护代码片段 用来保护代码片段 ,保证任何时刻只能有一 保证任何时刻只能有一 保证任何时刻只能有一 保证任何时刻只能有一 保证任何时刻只能有一 保证任何时刻只能有一 保证任何时刻只能有一 保证任何时刻只能有一 保证任何时刻只能有一 保证任何时刻只能有一 个线程执行被保护的代码 。
锁管理试图进入被保护代码段的线程 管理试图进入被保护代码段的线程 。
锁可拥有一个或多相关 条件对象 条件对象 条件对象 条件对象 。
每个 条件对象管理 条件对象管理 条件对象管理 条件对象管理 条件对象管理 条件对象管理 那些已经进入被保护的代码 那些已经进入被保护的代码 那些已经进入被保护的代码 那些已经进入被保护的代码 那些已经进入被保护的代码 那些已经进入被保护的代码 那些已经进入被保护的代码 那些已经进入被保护的代码 那些已经进入被保护的代码 那些已经进入被保护的代码 那些已经进入被保护的代码 那些已经进入被保护的代码 段但还不能运行的线程 。
解决方案二: synchronized synchronized synchronized 关键字 关
synchronized 关键字作用:
某个类内方法用 某个类内方法用 某个类内方法用 某个类内方法用 某个类内方法用 某个类内方法用 某个类内方法用 synchronizedsynchronizedsynchronizedsynchronizedsynchronizedsynchronizedsynchronized synchronizedsynchronized synchronized修饰后 修饰后 修饰后 ,该方 法被称为同步方;
只要某个线程正在访问同步方法 只要某个线程正在访问同步方法 只要某个线程正在访问同步方法 只要某个线程正在访问同步方法 只要某个线程正在访问同步方法 只要某个线程正在访问同步方法 只要某个线程正在访问同步方法 只要某个线程正在访问同步方法 只要某个线程正在访问同步方法 只要某个线程正在访问同步方法 只要某个线程正在访问同步方法 只要某个线程正在访问同步方法 只要某个线程正在访问同步方法 只要某个线程正在访问同步方法 ,其他线程 其他线程 其他线程 其他线程 欲要访问同步方法就被阻塞 欲要访问同步方法就被阻塞 欲要访问同步方法就被阻塞 欲要访问同步方法就被阻塞 欲要访问同步方法就被阻塞 欲要访问同步方法就被阻塞 欲要访问同步方法就被阻塞 欲要访问同步方法就被阻塞 欲要访问同步方法就被阻塞 欲要访问同步方法就被阻塞 欲要访问同步方法就被阻塞 欲要访问同步方法就被阻塞 ,直至线程从同 直至线程从同 直至线程从同 直至线程从同 直至线程从同 直至线程从同 步方法返回前唤醒被阻塞线程 步方法返回前唤醒被阻塞线程 步方法返回前唤醒被阻塞线程 步方法返回前唤醒被阻塞线程 步方法返回前唤醒被阻塞线程 步方法返回前唤醒被阻塞线程 步方法返回前唤醒被阻塞线程 步方法返回前唤醒被阻塞线程 步方法返回前唤醒被阻塞线程 步方法返回前唤醒被阻塞线程 步方法返回前唤醒被阻塞线程 步方法返回前唤醒被阻塞线程 步方法返回前唤醒被阻塞线程 ,其他线程方 其他线程方 其他线程方 其他线程方 其他线程方 可能进入同步方法 。
在同步方法中使用 wait() wait()、notify notify notify 和notifyAll notifyAll notifyAllnotifyAll () 方法 (见教材 656 页
一个线程在使用的同步方法中时,可能根据问题 一个线程在使用的同步方法中时,可能根据问题 一个线程在使用的同步方法中时,可能根据问题 一个线程在使用的同步方法中时,可能根据问题 的需要,必须使用 wait() wait()方法使本线程等待,暂 方法使本线程等待,暂 方法使本线程等待,暂 方法使本线程等待,暂 方法使本线程等待,暂 方法使本线程等待,暂 方法使本线程等待,暂 方法使本线程等待,暂 方法使本线程等待,暂 方法使本线程等待,暂 时让出 CPU 的使用权,并允许其它线程这个 的使用权,并允许其它线程这个 的使用权,并允许其它线程这个 的使用权,并允许其它线程这个 的使用权,并允许其它线程这个 的使用权,并允许其它线程这个 的使用权,并允许其它线程这个 的使用权,并允许其它线程这个 的使用权,并允许其它线程这个 的使用权,并允许其它线程这个 的使用权,并允许其它线程这个 的使用权,并允许其它线程这个 的使用权,并允许其它线程这个 的使用权,并允许其它线程这个 的使用权,并允许其它线程这个 的使用权,并允许其它线程这个 同步方法。
线程如果用完同步方法,应当执行 线程如果用完同步方法,应当执行 notifyAll notifyAllnotifyAll () 方 法通知所有由于使用这个同步方而处等待的 法通知所有由于使用这个同步方而处等待的 法通知所有由于使用这个同步方而处等待的 法通知所有由于使用这个同步方而处等待的 线程结束等待。
(2) 线程综合编程练习
2、实验内容和步骤
实验1:测试程序并进行代码注释。
测试程序1:
l 在Elipse环境下调试教材651页程序14-7,结合程序运行结果理解程序;
l 掌握利用锁对象和条件对象实现的多线程同步技术。
package synch; /**
* This program shows how multiple threads can safely access a data structure.
* @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();
}
}
}
package synch; import java.util.*;
import java.util.concurrent.locks.*; /**
* A bank with a number of bank accounts that uses locks for serializing access.
* @version 1.30 2004-08-01
* @author Cay Horstmann
*/
public class Bank
{
private final double[] accounts;
private Lock bankLock;
private Condition sufficientFunds; /**
* Constructs the bank.
* @param n the number of accounts
* @param initialBalance the initial balance for each account
*/
public Bank(int n, double initialBalance)
{
accounts = new double[n];
Arrays.fill(accounts, initialBalance);
bankLock = new ReentrantLock();
sufficientFunds = bankLock.newCondition();
} /**
* Transfers money from one account to another.
* @param from the account to transfer from
* @param to the account to transfer to
* @param amount the amount to transfer
*/
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();
}
} /**
* Gets the sum of all account balances.
* @return the total balance
*/
public double getTotalBalance()
{
bankLock.lock();
try
{
double sum = 0; for (double a : accounts)
sum += a; return sum;
}
finally
{
bankLock.unlock();
}
} /**
* Gets the number of accounts in the bank.
* @return the number of accounts
*/
public int size()
{
return accounts.length;
}
}

测试程序2:
l 在Elipse环境下调试教材655页程序14-8,结合程序运行结果理解程序;
l 掌握synchronized在多线程同步中的应用。
package synch2; import java.util.*; /**
* A bank with a number of bank accounts that uses synchronization primitives.
* @version 1.30 2004-08-01
* @author Cay Horstmann
*/
public class Bank
{
private final double[] accounts; /**
* Constructs the bank.
* @param n the number of accounts
* @param initialBalance the initial balance for each account
*/
public Bank(int n, double initialBalance)
{
accounts = new double[n];
Arrays.fill(accounts, initialBalance);
} /**
* Transfers money from one account to another.
* @param from the account to transfer from
* @param to the account to transfer to
* @param amount the amount to transfer
*/
public synchronized void transfer(int from, int to, double amount) throws InterruptedException
{
while (accounts[from] < amount)
wait();
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();
} /**
* Gets the sum of all account balances.
* @return the total balance
*/
public synchronized double getTotalBalance()
{
double sum = 0; for (double a : accounts)
sum += a; return sum;
} /**
* Gets the number of accounts in the bank.
* @return the number of accounts
*/
public int size()
{
return accounts.length;
}
}
package synch2; import java.util.*; /**
* A bank with a number of bank accounts that uses synchronization primitives.
* @version 1.30 2004-08-01
* @author Cay Horstmann
*/
public class Bank
{
private final double[] accounts; /**
* Constructs the bank.
* @param n the number of accounts
* @param initialBalance the initial balance for each account
*/
public Bank(int n, double initialBalance)
{
accounts = new double[n];
Arrays.fill(accounts, initialBalance);
} /**
* Transfers money from one account to another.
* @param from the account to transfer from
* @param to the account to transfer to
* @param amount the amount to transfer
*/
public synchronized void transfer(int from, int to, double amount) throws InterruptedException
{
while (accounts[from] < amount)
wait();
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();
} /**
* Gets the sum of all account balances.
* @return the total balance
*/
public synchronized double getTotalBalance()
{
double sum = 0; for (double a : accounts)
sum += a; return sum;
} /**
* Gets the number of accounts in the bank.
* @return the number of accounts
*/
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(); } } |

package synch3;
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 shoupiao;
public class Ticket implements Runnable {
public int num = 0;
Object obj = new Object();
public void run() {
while (true) {
// 关键字后的小括号表示锁,锁可以是程序中的任意一个对象
synchronized (obj) {
if (num >= 10) { //系统默认测试数据10张车票
break;
}
try {
// 当线程睡眠时锁不会开
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
num++;
if(num<10){
System.out.println(Thread.currentThread().getName() + "第"+num+"张票" );
}else{
System.out.println(Thread.currentThread().getName() + "第"+num+"张票" );
}
}
}
}
public static void main(String[] args) {
Ticket ticket = new Ticket();
//1.创建购票线程
Thread t1 = new Thread(ticket, "Thread-0窗口售:");
Thread t2 = new Thread(ticket, "Thread-1窗口售:");
Thread t3 = new Thread(ticket, "Thread-2窗口售:");
//2.开启购票点(模拟3个线程)测试购票
System.out.println("---------------------------------");
System.out.println("售票系统");
System.out.println("---------------------------------");
System.out.println("系统当前在线剩余总票数:10张");
t1.start();
t2.start();
t3.start();
}
}

实验总结:通过对多线程的进一步学习,理解了线程中各种状态代表的含义,以及如何调用,运行的原理,理解和掌握了线程的优先级属性及调度方法,线程同步的概念及实现技术。通过多线程的运用,实现了多个程序同步运行,以及各个程序在运行期间各种状态如何合理有序的切换
201771010126 王燕《面向对象程序设计(Java)》第十七周学习总结的更多相关文章
- 201771010134杨其菊《面向对象程序设计java》第九周学习总结
第九周学习总结 第一部分:理论知识 异常.断言和调试.日志 1.捕获 ...
- 201871010132-张潇潇《面向对象程序设计(java)》第一周学习总结
面向对象程序设计(Java) 博文正文开头 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cn ...
- 扎西平措 201571030332《面向对象程序设计 Java 》第一周学习总结
<面向对象程序设计(java)>第一周学习总结 正文开头: 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 ...
- 201871010124 王生涛《面向对象程序设计JAVA》第一周学习总结
项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://edu.cnblogs.com/campus/xbsf/ ...
- 杨其菊201771010134《面向对象程序设计Java》第二周学习总结
第三章 Java基本程序设计结构 第一部分:(理论知识部分) 本章主要学习:基本内容:数据类型:变量:运算符:类型转换,字符串,输入输出,控制流程,大数值以及数组. 1.基本概念: 1)标识符:由字母 ...
- 201871010115——马北《面向对象程序设计JAVA》第二周学习总结
项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...
- 201777010217-金云馨《面向对象程序设计(Java)》第二周学习总结
项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...
- 201871010132——张潇潇《面向对象程序设计JAVA》第二周学习总结
项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...
- 201771010123汪慧和《面向对象程序设计Java》第二周学习总结
一.理论知识部分 1.标识符由字母.下划线.美元符号和数字组成, 且第一个符号不能为数字.标识符可用作: 类名.变量名.方法名.数组名.文件名等.第二部分:理论知识学习部分 2.关键字就是Java语言 ...
- 马凯军201771010116《面向对象与程序设计Java》第九周学习总结
一.理论知识部分 异常.日志.断言和调试 1.异常:在程序的执行过程中所发生的异常事件,它中断指令的正常执行. 2.Java的异常处理机制可以控制程序从错误产生的位置转移到能够进行错误处理的位置. 3 ...
随机推荐
- JustSoso笔记
当时想了大半天,想着到底要怎么绕过MD5呢,结果还是没做出来,即使问了学长,自己还是漏了一个步骤,file=hint.php,特此笔记,又学到了个引用变量的知识 学习自 https://www.ctf ...
- apache无法启动报错No space left on device
apache无法启动报错No space left on device 故障现象:apache无法启动ipcs信号量很多 # service httpd startStarting httpd : [ ...
- Allowed memory size of 134217728 bytes exhausted
错误信息: Allowed memory size of 134217728 bytes exhausted (tried to allocate 65015808 bytes) 由于报错信息和数据库 ...
- Xshell 连接虚拟机出现 "The remote SSH server rejected X11 forwarding request"
1. 描述 虚拟机:VirtualBox Linux: centOS7 解决了 centOS7在VirtualBox中装好后的网络连接问题 后,用 Xshell 连接服务器时出现下面情况: 2. ss ...
- 学习 razor pages 指南
这是一个系列,我打算把此人的系列翻译一下,学习技术的同时,顺便提高一下英文水平. 原文地址:https://www.learnrazorpages.com/ 前言 欢迎来学习 razor pages ...
- 个人版整理APP测试流程
2016.1.5 我的笔记 一 .APP测试基本流程 1.1 测试周期 测试周期可按项目的开发周期来确定测试时间,一般测试时间为两三周(即15个工作日),根据项目情况以及版本质量可适当缩短或延长测试 ...
- vue 统一处理token失效问题
使用http response 拦截器 在main.js中添加 import axios from 'axios'; axios.interceptors.response.use(response ...
- LoadRunner脚本准备
脚本录制1.启动LoadRunner2.打开VuGen在LoadRunner Launcher窗格中,单击创建/编辑脚本3.创建一个空白Web脚本在“新建虚拟用户”对话框里选择新建脚本的协议一般选择W ...
- 2-3、配置Filebeat
配置Filebeat 提示:Filebeat modules为常见的日志格式提供了最快的入门操作. 如果要使用Filebeat模块,请跳过本节,包括剩余的入门步骤,并直接转到快速入门:Quick st ...
- linux命令详解之df命令
df命令概述df命令作用是列出文件系统的整体磁盘空间使用情况.可以用来查看磁盘已被使用多少空间和还剩余多少空间. df命令显示系统中包含每个文件名参数的磁盘使用情况,如果没有文件名参数,则显示所有当前 ...