实验十七  线程同步控制

实验时间 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)》第十七周学习总结的更多相关文章

  1. 201771010134杨其菊《面向对象程序设计java》第九周学习总结

                                                                      第九周学习总结 第一部分:理论知识 异常.断言和调试.日志 1.捕获 ...

  2. 201871010132-张潇潇《面向对象程序设计(java)》第一周学习总结

    面向对象程序设计(Java) 博文正文开头 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cn ...

  3. 扎西平措 201571030332《面向对象程序设计 Java 》第一周学习总结

    <面向对象程序设计(java)>第一周学习总结 正文开头: 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 ...

  4. 201871010124 王生涛《面向对象程序设计JAVA》第一周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://edu.cnblogs.com/campus/xbsf/ ...

  5. 杨其菊201771010134《面向对象程序设计Java》第二周学习总结

    第三章 Java基本程序设计结构 第一部分:(理论知识部分) 本章主要学习:基本内容:数据类型:变量:运算符:类型转换,字符串,输入输出,控制流程,大数值以及数组. 1.基本概念: 1)标识符:由字母 ...

  6. 201871010115——马北《面向对象程序设计JAVA》第二周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...

  7. 201777010217-金云馨《面向对象程序设计(Java)》第二周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...

  8. 201871010132——张潇潇《面向对象程序设计JAVA》第二周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...

  9. 201771010123汪慧和《面向对象程序设计Java》第二周学习总结

    一.理论知识部分 1.标识符由字母.下划线.美元符号和数字组成, 且第一个符号不能为数字.标识符可用作: 类名.变量名.方法名.数组名.文件名等.第二部分:理论知识学习部分 2.关键字就是Java语言 ...

  10. 马凯军201771010116《面向对象与程序设计Java》第九周学习总结

    一.理论知识部分 异常.日志.断言和调试 1.异常:在程序的执行过程中所发生的异常事件,它中断指令的正常执行. 2.Java的异常处理机制可以控制程序从错误产生的位置转移到能够进行错误处理的位置. 3 ...

随机推荐

  1. return *this和return this有什么区别?

    return *this返回的是当前对象的克隆或者本身(若返回类型为A, 则是克隆, 若返回类型为A&, 则是本身 ). return this返回当前对象的地址(指向当前对象的指针). 转: ...

  2. United States Department of Agriculture 美国农业部网站数据自动下载小脚本

    帮对象写的自动点击页面的小脚本,如果有需要的可以试试,(#^.^#) https://apps.fas.usda.gov/gats/ExpressQuery1.aspx var year = '199 ...

  3. jmeter 压力测试安装教程

    条件: 安装java8,没有安装点击:https://www.cnblogs.com/xdtx/p/10188767.html 进入官网下载:http://jmeter.apache.org/ 配置环 ...

  4. C# 用Serializer.ToXml()方法转换成两种格式的XML

    常见XML格式两种: 这种是属性的格式,实体的Model属性上面加上这个特性 [XmlAttribute] <AAA aa="/> 这种是标签的格式,实体的Model属性上面加上 ...

  5. Py西游攻关之Socket网络编程

    新闻 管理   Py西游攻关之Socket网络编程   知识预览 计算机网络 回到顶部 网络通信要素: A:IP地址   (1) 用来标识网络上一台独立的主机 (2) IP地址 = 网络地址 + 主机 ...

  6. Git管理源代码

    Git Git 是目前世界上最先进的分布式版本控制系统(没有之一) 作用 源代码管理 为什么要进行源代码管理? 方便多人协同开发 方便版本控制 Git单人本地仓库操作 安装git sudo apt-g ...

  7. YARN配置

    环境搭建 mapred-site.xml <configuration> <property> <name>mapreduce.framework.name< ...

  8. Windows Internals 笔记——线程调度

    1.线程内核对象中的CONTEXT反应了线程上一次执行时CPU寄存器的状态.大约每隔20ms,Windows都会查看所有当前存在的线程内核对象.Windows在可调度的线程内核对象中选择一个,并将上次 ...

  9. echarts 隐藏Y轴最大最小值label及分割线 ----障眼大发好使

    需求图 1====>label 最大最小值还好弄, yAxis{ axisLabel{ showMinLabel: false, showMaxLabel: false, }} 2====> ...

  10. 生成免费SSL通配证书

    通过Let's Encrypt 生成免费SSL证书 有效期是3个月 1.下载工具certbot-auto wget https://dl.eff.org/certbot-auto chmod +x c ...