王颖奇 20171010129《面向对象程序设计(java)》第十七周学习总结
实验十七 线程同步控制
实验时间 2018-12-10
学习总结:
1.Java通过多线程的并发运行提高系统资源利用 率,改善系统性能。
2.假设有两个或两个以上的线程共享 某个对象,每个线程都调用了改变该对象类状态的方法,就会引起的不确定性。
3.多线程并发执行中的问题
◆多个线程相对执行的顺序是不确定的。
◆线程执行顺序的不确定性会产生执行结果的不确定性。
◆在多线程对共享数据操作时常常会产生这种不确定性。
4.多线程并发运行不确定性问题解决方案:引入线程同步机制。
5.(1)锁对象与条件对象
用ReentrantLock保护代码块的基本结构如下:
myLock.lock();
try { critical section }
finally{
myLock.unlock();
}
(2)synchronized关键字
synchronized关键字作用:
➢ 某个类内方法用synchronized 修饰后,该方 法被称为同步方法;
➢ 只要某个线程正在访问同步方法,其他线程 欲要访问同步方法就被阻塞,直至线程从同 步方法返回前唤醒被阻塞线程,其他线程方 可能进入同步方法。
具体用法参考博客:https://blog.csdn.net/sinat_32588261/article/details/72880159
1、实验目的与要求
(1) 掌握线程同步的概念及实现技术;
(2) 线程综合编程练习
2、实验内容和步骤
实验1:测试程序并进行代码注释。
测试程序1:
l 在Elipse环境下调试教材651页程序14-7,结合程序运行结果理解程序;
l 掌握利用锁对象和条件对象实现的多线程同步技术。
代码:
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.signal();
}
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;
}
}
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();
}
}
}
运行结果:

测试程序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();//解除那些在该对象上调用wait方法的线程阻塞状态。该方法只能在同步方法或同步块内部调用。
} /**
* 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; /**
* This program shows how multiple threads can safely access a data structure,
* using synchronized methods.
* @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();
}
}
}
运行结果:

测试程序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(); } } |
存在的问题:
两个线程各自运行自己的

运行的预期结果应该为:
最终的s=1200
更正思路:
增加语句
synchronized
代码:
package demo;
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 ThreadTest;
public class Demo {
public static void main(String[] args) {
Mythread mythread = new Mythread();
Thread t1 = new Thread(mythread);
Thread t2 = new Thread(mythread);
Thread t3 = new Thread(mythread);
t1.start();
t2.start();
t3.start();
}
}
class Mythread implements Runnable {
int t = 1;
boolean flag = true;
public void run() {
// TODO Auto-generated method stub
while (flag) {
try {
Thread.sleep(500);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
synchronized (this) {
if (t <= 10) {
System.out.println(Thread.currentThread().getName() + "窗口售:第" + t + "张票");
t++;
}
if (t > 10) {
flag = false;
}
}
}
}
}
运行结果:

代码:

package ThreadTest;
public class Demo1 extends Thread {
static int t = 1;
public void run() {
synchronized (this) {
while (t <= 10) {
if (t <= 10) {
System.out.println(Thread.currentThread().getName() + "窗口售:第" + t + "张票");
t++;
} else {
System.out.println("票卖完了");
}
}
try {
sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Demo1 window1 = new Demo1();
Demo1 window2 = new Demo1();
Demo1 window3 = new Demo1();
window1.start();
window2.start();
window3.start();
}
}
运行结果:


王颖奇 20171010129《面向对象程序设计(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/ 这个作业的要求在哪里 ...
- 杨其菊201771010134《面向对象程序设计Java》第二周学习总结
第三章 Java基本程序设计结构 第一部分:(理论知识部分) 本章主要学习:基本内容:数据类型:变量:运算符:类型转换,字符串,输入输出,控制流程,大数值以及数组. 1.基本概念: 1)标识符:由字母 ...
- 201871010124 王生涛《面向对象程序设计JAVA》第一周学习总结
项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://edu.cnblogs.com/campus/xbsf/ ...
- 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 ...
随机推荐
- 微服务框架-Spring Cloud
Spring Cloud入门 微服务与微服务架构 微服务架构是一种新型的系统架构.其设计思路是,将单体架构系统拆分为多个可以相互调用.配合的独立运行的小程序.这每个小程序对整体系统所提供的功能就称为微 ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(六)之Initialization & Cleanup
Two of these safety issues are initialization and cleanup. initialization -> bug cleanup -> ru ...
- js操作svg整体缩放
首先我们先创建一个svg整体布局,代码如下: <!DOCTYPE html> <html> <head> <title>js操作svg实现整体缩放< ...
- Python巩固 - 第N天
一.函数解释: def fact(n, m = 1): s = 1 for j in range(1, n+1): s = s*j return n, m, s//m print(fact(10, 5 ...
- 人体和电脑的关系——鸟哥的LINUX私房菜基础学习篇读书笔记
CUP=脑袋: 每个人会做的事情都不一样(指令集的差异),但主要都是通过脑袋来判断与控制身体各部分的行动 内存=脑袋中存放正在思考的数据区块: 在实际活动过程中,我们的脑袋需要有外界刺激的数据(例如光 ...
- Nacos - 阿里开源配置中心
配置中心相信大家都有听过,zookeeper.apollo等等都是配置中心的代表,但大部分都是JAVA系为主的,笔者主要开发语言使用的是Golang当然也有类似于ETCD这样的组件,但是并不方便管理也 ...
- 异常处理的方式二:throws+异常类型
package com.yhqtv.demo01Exception; import java.io.File; import java.io.FileInputStream; import java. ...
- 深入分析Redis的主从复制机制
一.前言 最近由于疫情影响,时间比较多,所以开始学习之前一直想学,但是却没时间学的Redis.这两天研究了一下Redis的持久化以及主从复制机制,现在已经很晚了,就不多废话了.这篇博客就来谈一谈R ...
- Go语言 2019 调查报告发布
Go 官方博客昨日公布了[ 2019 年 Go 语言调查报告].本次调查收到的回复达到 10,975 份,约为去年的两倍. 这些受访者的反馈意见将被选取用于改进 Go 语言的发展. 以下是 2019 ...
- 使用vue.js封装一个包含图片的跑马灯组件
初衷: 学习完Vuejs后,来准备练习仿写一下老东家的门户页面,主要是为了熟悉一下常用插件的使用,比如video.js,wow.js,swiper等等:而其中涉及到一个包含图片跑马灯组件,大概长这样( ...