实验十七  线程同步控制

实验时间 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实验作业的更多相关文章

  1. 第十八周java实验作业

    实验十八  总复习 实验时间 2018-12-30 1.实验目的与要求 (1) 综合掌握java基本程序结构: (2) 综合掌握java面向对象程序设计特点: (3) 综合掌握java GUI 程序设 ...

  2. 第十五周java实验作业

    实验十五  GUI编程练习与应用程序部署 实验时间 2018-12-6 1.实验目的与要求 (1) 掌握Java应用程序的打包操作: Java程序的打包,程序编译完成后,程序员将.class文件压缩打 ...

  3. 第十六周Java实验作业

    实验十六  线程技术 实验时间 2017-12-8 1.实验目的与要求 (1) 掌握线程概念: 多线程是进程执行过程中产生的多条执行线索,线程是比进程执行更小的单位. 线程不能独立存在,必须存在于进程 ...

  4. 第十二周java实验作业

    实验十二  图形程序设计 实验时间 2018-11-14 1.实验目的与要求 (1) 掌握Java GUI中框架创建及属性设置中常用类的API: Java的集合框架实现了对各种数据结构的封装. jav ...

  5. 第十一周Java实验作业

    实验十一   集合 实验时间 2018-11-8 1.实验目的与要求 (1) 掌握Vetor.Stack.Hashtable三个类的用途及常用API: Vector类类似长度可变的数组,其中只能存放对 ...

  6. 第十周Java实验作业

    实验十  泛型程序设计技术 实验时间 2018-11-1 1.实验目的与要求 (1) 理解泛型概念: 泛型:也称参数化类型,就是在定义类,接口和方法时,通过类型参数只是将要处理的类型对象.(如Arra ...

  7. 第九周Java实验作业

    实验九 异常.断言与日志 实验时间 2018-10-25 1.实验目的与要求 (1) 掌握java异常处理技术: Java的异常处理机制可以控制程序从错误产生的位置转移到能够进行错误处理的位置. Ja ...

  8. 第八周Java实验作业

    实验六 接口的定义与使用 实验时间 2018-10-18 1.实验目的与要求 (1) 掌握接口定义方法: 声明:  public interface 接口名 {...} 接口体中包含常量定义和方法定义 ...

  9. 第七周java实验作业

    实验七 继承附加实验实验时间 2018-10-11 1.实验目的与要求 (1)进一步理解4个成员访问权限修饰符的用途: Public  该类或非该类均可访问 Private  只有该类可以访问 Pro ...

随机推荐

  1. Find a way (广度优先搜索)

    题目: Pass a year learning in Hangzhou, yifenfei arrival hometown Ningbo at finally. Leave Ningbo one ...

  2. C++走向远洋——61(项目一、排序函数模板)

    */ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.cpp * 作者:常轩 * 微信公众号:Worldhe ...

  3. 关于Markdown下无法使用表格的解决方案

    关于Markdown下无法使用表格的解决方案 写表格,出现如下场景 解决方法.点击左下角M的表示,切换到extra模式 打开了新世界.如果不能点击,估计是你没有激活pro的权限,百度下就可以了. 或者 ...

  4. linux 下修改最大文件数

    环境为centosV7系列 1.查看进程的打开最大文件数,默认为1024 [root@localhost ~]# ulimit -a core file size (blocks, -c) 0 dat ...

  5. Matplotlib数据可视化(5):柱状图与直方图

      柱状图和直方图是两种非常类似的统计图,区别在于: 直方图展示数据的分布,柱状图比较数据的大小. 直方图X轴为定量数据,柱状图X轴为分类数据.因此,直方图上的每个条形都是不可移动的,X轴上的区间是连 ...

  6. Linux系统系统盘扩容

    在Linux学习过程中,可能会遇到根目录存储空间不足的问题,这时候如果只是新增一块硬盘并挂载到某个目录上,还需要将数据转移至新的硬盘中才能缓解存储压力.这种操作未免有些繁琐,那可不可以直接对跟目录进行 ...

  7. 微信小程序用setData修改数组或对象中的一个属性值,超好用,最简单的实现方法,不容错过!大神们 都 在 看 的方法!!!

    在page中 data: { info: [{ name: "yuki", tou: "../img/head.jpg", zGong: 130, gMoney ...

  8. 学习ConcurrentHashMap并发写机制

    1. 前言 上篇文章讲了 Unsafe 类中 CAS 的实现,其实是在为这篇文章打基础.不太熟悉的小伙伴请移步Unsafe 中 CAS 的实现.本篇文章主要基于 OpenJDK8 来做源码解析. 2. ...

  9. 探究Spring Boot中的接收参数问题与客户端发送请求传递数据

    结合此篇参考Spring框架学习笔记(9)--API接口设计相关知识及具体编码实现 在使用Spring Boot进行接收参数的时候,发现了许多问题,之前一直都很忙,最近才稍微有空研究一下此问题. 网上 ...

  10. List remove ConcurrentModificationException源码分析

    代码块 Java         Exception in thread "main" java.util.ConcurrentModificationException at j ...