1、实验目的与要求

(1) 掌握线程同步的概念及实现技术;

(2) 线程综合编程练习

一、理论知识

⚫ 线程同步

(1)多线程并发运行不确定性问题解决方案:引入线 程同步机制,使得另一线程要使用该方法,就只 能等待

(2)在Java中解决多线程同步问题的方法有两种:

解决方案一:锁对象与条件对象

用ReentrantLock保护代码块的基本结构如下: myLock.lock();

try { critical section }

finally{ myLock.unlock(); }

(3)解决方案二: synchronized关键字

synchronized关键字作用: ➢ 某个类内方法用synchronized 修饰后,该方 法被称为同步方法;

➢ 只要某个线程正在访问同步方法,其他线程欲要访问同步方法就被阻塞,直至线程从同步方法返回前唤醒被阻塞线程,其他线程方可能进入同步方法。

(4)在同步方法中使用wait()、notify 和notifyAll()方法

一个线程在使用的同步方法中时,可能根据问题 的需要,必须使用wait()方法使本线程等待,暂 时让出CPU的使用权,并允许其它线程使用这个 同步方法。

线程如果用完同步方法,应当执行notifyAll()方 法通知所有由于使用这个同步方法而处于等待的 线程结束等待。

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();//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;
}
}

bank

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();
}
}
}

SynchBank

测试程序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;
}
}

Bank

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();
}
}
}

SynchBankTest2

结果如下:

测试程序3:

l 在Elipse环境下运行以下程序,结合程序运行结果分析程序存在问题;

尝试解决程序中存在问题。

package B;
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();
}
}

Thread3

实验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张票

代码如下:

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() {
while (flag) {
try {
Thread.sleep(500);
}
catch(InterruptedException e)
{
e.printStackTrace();
} synchronized(this) {
if(t<=10) {
System.out.println(Thread.currentThread().getName()+"窗口售:第"+t+"张票");
t++;
}
if(t>10) {
flag=false;
}
} }
}
}

Demo

结果如下:

 三、实验总结

本次作业我们学习了线程同步的知识,在测试程序中更深一步的理解了理论知识,发现了线程的多变性,希望在接下来额学习中可以更好的运用。

201771010135 杨蓉庆《面对对象程序设计(java)》第十七周学习总结的更多相关文章

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

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

  2. 201771010135杨蓉庆《面向对象程序设计(java)》第四周学习总结

    学习目标 1.掌握类与对象的基础概念,理解类与对象的关系: 2.掌握对象与对象变量的关系: 3.掌握预定义类的基本使用方法,熟悉Math类.String类.math类.Scanner类.LocalDa ...

  3. 201771010135杨蓉庆 《面向对象程序设计(java)》第三周学习总结

    一:第1-3章学习内容: 第一章:复习基本数据类型 整型 byte(1个字节 表示范围:-2^7 ~ (2^7)-1) short(2个字节 表示范围:-2^15~(2^15)-1) int(4个字节 ...

  4. 201771010135杨蓉庆《面向对象程序设计(java)》第六周学习总结

    实验六 继承定义与使用 1.实验目的与要求 (1) 理解继承的定义: (2) 掌握子类的定义要求 (3) 掌握多态性的概念及用法: (4) 掌握抽象类的定义及用途: (5) 掌握类中4个成员访问权限修 ...

  5. 201771010135杨蓉庆《面向对象程序设计(java)》第二周学习总结

    第一部分:理论知识学习部分 3.1 标识符:由字母.下划线.美元符号和数字组成, 且第一个符号不能为数字,可用作:类名.变量名.方法名.数组名.文件名等.有Hello.$1234.程序名.www_12 ...

  6. 201771010135 杨蓉庆/张燕《面对对象程序设计(java)》第十三周学习总结

    1.实验目的与要求 (1) 掌握事件处理的基本原理,理解其用途: (2) 掌握AWT事件模型的工作机制: (3) 掌握事件处理的基本编程模型: (4) 了解GUI界面组件观感设置方法: (5) 掌握W ...

  7. 201771010135 杨蓉庆《2018面向对象程序设计(java)课程学习进度条》

                                                                                                        ...

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

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

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

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

  10. 201771010135 杨蓉庆《面对对象程序设计(java)》第十八周学习总结

    1.实验目的与要求 (1) 综合掌握java基本程序结构: (2) 综合掌握java面向对象程序设计特点: (3) 综合掌握java GUI 程序设计结构: (4) 综合掌握java多线程编程模型: ...

随机推荐

  1. 题解【Codeforces859C】Pie Rules

    题面 一道需要一定思考的 \(\text{DP}\) . 设 \(dp_i\) 表示第 \(i\) 步走的人能得到的最大分数, \(sum_i\) 表示 \(\sum_{j=i}^n a_j\) ,即 ...

  2. OpenShift 4.3环境中创建基于Go的Operator

    详细步骤可以参考官方文档 https://docs.openshift.com/container-platform/4.3/operators/operator_sdk/osdk-getting-s ...

  3. 小匠第二周期打卡笔记-Task03

    一.过拟合欠拟合及其解决方案 知识点记录 模型选择.过拟合和欠拟合: 训练误差和泛化误差: 训练误差 :模型在训练数据集上表现出的误差, 泛化误差 : 模型在任意一个测试数据样本上表现出的误差的期望, ...

  4. flask入门(一)

    flask是一个轻量级的框架,据说跟django跟比是真的轻. 首先要先配置一个虚拟环境,flask项目需要在那个虚拟环境里运行,这里需要用的venv库实在python3里的标准库,不过有的linux ...

  5. AcWing 827. 双链表

    https://www.acwing.com/problem/content/829/ #include <iostream> using namespace std; ; int m; ...

  6. 小匠第一周期打卡笔记-Task01

    一.线性回归 知识点记录 线性回归输出是一个连续值,因此适用于回归问题.如预测房屋价格.气温.销售额等连续值的问题.是单层神经网络. 线性判别模型 判别模型 性质:建模预测变量和观测变量之间的关系,亦 ...

  7. centos 7 安装 nginx maxmind GEO IP IP库相关部署

    centos 7 上为nginx 增加Geo IP的功能 yum install gcc gcc-c++ make automake autoconf libtool wget unzip -y if ...

  8. LVM逻辑卷:创建LVM分区实例

    一.概述 LVM(Logical Volume Manager)是基于内核的一种逻辑卷管理器,LVM适合于管理大存储设备,并允许用户动态调整文件系统的大小.此外LVM快照功能可以帮助我们快速备份数据. ...

  9. Codeforces C. Almost Equal (数学规律)

    题目链接:http://codeforces.com/contest/1206/problem/C 题解 : 观察可以发现当n为偶数时,1 - 2n是不满足题意的,可以举例n = 2,n = 4试一试 ...

  10. ThinkPhp5 中Volist标签的用法

    Volist标签一般是和内置方法assign()搭配使用,将值从后台传到前台,是当下比较流行的一种传值方法 本文实例讲述了ThinkPHP模板循环输出Volist标签用法.分享给大家供大家参考,具体如 ...