成绩:面向对象原理与Java实践课程实验报告实验6:多线程实验姓名林浩强班级网络14-2学号 14034460220实验地点软件实验室实验时间 2016.6.7指导教师姚明一、实验目的:●了解线程调度机制●理解线程同步机制●掌握线程设计方法二、实验要求:●掌握线程创建的方法●掌握线程的基本控制方法●掌握线程间的同步控制方法三、实验内容:1、随机生成1万个整数,利用线程技术计算两种不同排序算法对这些数排序的运行时间。
2、有一水塘,可实现注水和排水操作。
当水塘无水时不能对其再进行排水操作,当水塘水满时不能对其再进行注水操作。
创建水塘类Pond、注水线程Injection和排水线程Drain,假设注水线程可以在10分钟内将水塘注满水,排水线程可以在10分钟内将水塘的水全排出。
试实现水塘的注水和排水过程。
四、设计思路:首先,第一个实验的需求是随机生成10000个整数并且按两种算法排序,并利用线程的方式计算排序时间。
我用的排序算法是冒泡排序和选择排序法,在排序的前后分别用System 类的CurrentTimeMillis()方法获取当前时间的毫秒值,作差求出排序所用的时间。
最后在SortDemo类中启动线程即可。
、第二个实验的需求是实现注水和排水的操作,题目中指出“当水塘无水时不能对其再进行排水操作,当水塘水满时不能对其再进行注水操作”,所以我采用了线程的等待唤醒机制来实现。
首先在Pond类中声明一个标记变量flag,把注水和排水的操作封装成为功能并加了同步关键字synchronize,方法中运用了同步唤醒机制实现依次的一次一个输出。
然后在Injection类和Drain类中调用同步方法即可。
最后,在PondDemo中启动线程即可。
五、程序源代码:实验题目1:package java6_Test;import java.util.Random;public class Sort1 extends Thread {private Object obj = new Object();//重写run方法public void run() {//计时开始long l1 = System.currentTimeMillis();//用Object类对象设置同步锁synchronized (obj) {//随机生成10000个数并用相应长度数组来储存这些数int[] data = new int[10000];for (int x = 0; x < 10000; x++) {int b = r.nextInt();System.out.println(this.getName() + ":" + b);data[x] = b;}//调用自定义方法sort1sort1(data);//计时结束,计算所需的时间并输出long l2 = System.currentTimeMillis();System.out.println("共耗时"+(l2 - l1)+"毫秒");}}//冒泡排序法对数组中的数进行排序private synchronized void sort1(int[] data) {for (int x = 0; x < data.length - 1; x++) {for (int y = 0; y < data.length - 1 - x; y++) {if (data[y] > data[y + 1]) {int temp = data[y];data[y] = data[y + 1];data[y + 1] = temp;}}}System.out.println(this.getName()+"排序完成!");}}package java6_Test;import java.util.Random;public class Sort2 extends Thread {private Object obj = new Object();//重写run方法public void run() {//计时开始long l3 = System.currentTimeMillis();//用Object类对象设置同步锁synchronized (obj) {//随机生成10000个数并用相应长度数组来储存这些数int[] data = new int[10000];for (int x = 0; x < 10000; x++) {int b = r.nextInt();System.out.println(this.getName() + ":" + b);data[x] = b;}//调用自定义方法sort2sort2(data);//计时结束,计算所需的时间并输出long l4 = System.currentTimeMillis();System.out.println("共耗时" + (l4 - l3) + "毫秒");}}//选择排序法对数组中的数进行排序private synchronized void sort2(int[] data) {for (int x = 0; x < data.length - 1; x++) {for (int y = x + 1; y < data.length; y++) {if (data[y] < data[x]) {int temp = data[x];data[x] = data[y];data[y] = temp;}}}System.out.println(this.getName()+"排序完成!");}}package java6_Test;public class SortDemo {public static void main(String[] args) {//创建线程类的对象Sort1 s1 = new Sort1();Sort2 s2 = new Sort2();//启用线程s1、s2s1.start();s2.start();}}package java6_Test2;public class Pond {private boolean flag;//默认是没有数据,如果是true,说明有数据public synchronized void injection() {//如果没数据,就等待if (this.flag) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//注水过程System.out.println("注水十分钟");//修改标记并唤醒this.flag = true;this.notify();}public synchronized void drain() {//如果有数据,就等待if (!this.flag) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//排水过程System.out.println("排水十分钟");//修改标记并唤醒this.flag = false;this.notify();}}package java6_Test2;public class Injection implements Runnable { private Pond p;public Injection(Pond p) {this.p = p;}@Overridepublic void run() {while (true) {p.injection();}}}package java6_Test2;public class Drain implements Runnable {private Pond p;public Drain(Pond p) {super();this.p = p;}@Overridepublic void run() {while (true) {p.drain();}}}package java6_Test2;public class PondDemo {public static void main(String[] args) {//创建Pond资源类对象Pond p = new Pond();//创建注水类和排水类的对象Injection i = new Injection(p);Drain d = new Drain(p);//将注水类和排水类的对象作为参数调用线程类的对象Thread t1 = new Thread(i);Thread t2 = new Thread(d);//启动线程t1.start();t2.start();}}六、实验过程中遇到的问题及解决手段:在做实验任务一的时候,一开始没有设置同步锁对象,可能会出现问题,在线程执行过程中可能会被另外的线程执行了,这样的线程不是很安全。
在加了同步锁之后,便不会发生这样的问题,线程会等着另外一个线程执行完再抢CPU的执行权,这样会安全点。
在做实验任务二时,我一开始采用实验任务一的做法,在运行时发现,出现了注水程序连续运行了很多次,而排水程序也是出现连续运行的情况,并没有我们要求的依次一注水一排水这样的流程执行。
经过在贴吧里面提问,我找到了原因,原因很简单,在线程执行过程中,CPU的一点点时间片的执行权,就足够你执行很多次了。
所以,通过查阅资料,我了解到了Java提供的一种等待唤醒机制可以完美解决这个问题。
同时我也改进了程序,一开始我把同步锁放在Injection类和Drain类中,作为同步代码块包裹程序,后来我发现也可以把操作封装成同步方法,而在Injection和Drain类中只要调用方法即可。
七、本次实验的体会(结论):多线程编程又称并发编程,在完成实验的过程中,我初步理解了多线程的工作原理,也学会了使用多线程来完成一些操作,相信这对我以后的java基础知识的加深有很大的帮助。
另外,我也了解到了java提供的线程同步方式:synchronized 关键字和Object类的wait、notify和notifyAll方法。
虽然这些可能只是皮毛,但是我相信在以后的学习中我会学习到更多的东西并把他们运用到实际工作中。