课程  Java面向对象程序设计

一、实验目的

掌握多线程程序设计

二、实验环境

1、微型计算机一台

2、WINDOWS操作系统,Java SDK,Eclipse开发环境

三、实验内容

1、Java有两种实现多线程的方式:通过Runnable接口、通过Thread直接实现,请掌握这两种实现方式,并编写示例程序。

2、多线程是并发执行的,交替占有cpu执行,请编写示例程序,并观察输出结果。

3、编写程序实现生产者消费者问题代码,采用线程同步机制来解决多线程共享冲突问题。

四、实验步骤和结果

1、Java有两种实现多线程的方式:通过Runnable接口、通过Thread直接实现,请掌握这两种实现方式,并编写示例程序。

(1)通过Runnable接口实现多线程:

定义实现java.lang.Runnable接口的类,Runnable接口中只有一个run()方法,用来定义线程运行体。代码(MyRunner.java)如下:

package CreateThread;
import java.util.TreeMap; public class MyRunner implements Runnable{ //实现Runnable接口
public void run(){
for (int i = 0; i <20; i++) { //要在线程中执行的代码
System.out.println("MyRunner:"+i);
}
}
public static void main(String[] args) {
Thread thread1=new Thread(new MyRunner());
thread1.start();
}
}

程序执行结果截图如下:

(2)通过Thread实现多线程:将类定义为Thread类的子类,并重写run()方法。代码(MyThread.java)如下

package CreateThread;
public class MyThread extends Thread {
public void run(){
for (int i = 0; i < 10; i++) {
System.out.println("MyThread:"+i);
}
}
public static void main(String[] args) {
Thread thread2=new MyThread();
thread2.start();
}
}

2、多线程是并发执行的,交替占有cpu执行,编写示例程序如下,主线程先执行,然后启动两个新线程,但这两个新线程并没有立刻得到执行,而是统一由JVM根据时间片来调度,调度到哪个线程,就由哪个线程执行片刻。并且这两个新线程应该是交替显示结果,如果没有交替显示,可能是机器性能较好,在单位时间片内已经完成了循环运算,我们可以将循环次数更改为2000或更高值再行测试。多运行几次,每次的输出结果都不可能相同,说明JVM调度线程的执行顺序是随机的。

测试代码(ConcurrentExecutionThread.java)如下所示:

package CreateThread;
public class ConcurrentExecutionThread {
public static void main(String[] args) {
System.out.println("主线程开始执行");
Thread thread1=new Thread(new MyRunner());
thread1.start();
System.out.println("启动一个新线程(thread1)..."); Thread thread2=new MyThread();
thread2.start();
System.out.println("启动另一个新线程(thread2)...");
System.out.println("主线程执行完毕");
}
}

程序运行结果为:

3、编写程序实现生产者消费者问题代码,采用线程同步机制来解决多线程共享冲突问题。

(1)编写产品类

生产者要生产产品,消费者要消费产品,所以产品要提供一个含有标识的id属性,另外要在生产或消费时打印产品的详细内容,所以需要重写toString()方法,产品类(Products.java)代码如下:

package SynchronizedThread;
//编写产品类
public class Products {
int id;
public Products() {
super();
}
public Products(int id) {
super();
this.id = id;
}
public String toString() {
return "Products [id=" + id + "]";
}
}

(2)编写店员类(Clerk.java)

店员一次只能持有10份产品,如果生产者生产的产品多于10份,则会让当前的正在此对象上操作的线程等待。一个线程访问addProduct方法时,它已经拿到这个锁了,当遇到产品大于10份时,它会阻塞。而且,只有锁定对象后才可以用wait方法,否则会出错。并且,notify与wait一般是一一对应的。

package SynchronizedThread;
//编写店员类
public class Clerk {
int index=0;//默认为0个产品
Products[] pro=new Products[10];
//生产者生产出来的产品交给店员
public synchronized void addProduct(Products pd){
while (index==pro.length) {
try {
this.wait();//产品已满,请稍后再生产
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notify();//通知等待区的消费者可以取产品了
pro[index]=pd;
index++;
}
//消费者从店员处取产品
public synchronized Products getProduct(){
while (index==0) {
try {
this.wait(); //缺货,请稍后再取。
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notify();//通知等待区的生产者可以生产产品了
index--;
return pro[index];
}
}

(3)编写生产者线程类(Producer.java)

生产者与店员有关系,所以店员类被当做属性引入进来,通过构造器完成初始化店员类对象的任务。为了凸显效果,每生产一个产品后让线程睡眠一会儿。

package SynchronizedThread;
//编写生产者线程类
public class Producer implements Runnable { //生产者线程要执行的任务
private Clerk clerk;
public Producer() {
super();
}
public Producer(Clerk clerk) {
super();
this.clerk = clerk;
}
public void run() {
System.out.println("生产者开始生产产品");
for (int i = 0; i <15; i++) {//注意此处的循环次数一定要大于pro数组的长度(10)
Products pd=new Products(i);
clerk.addProduct(pd);//生产产品
System.out.println("生产了:"+pd);
try { //睡眠时间用随机产生的值来设置
Thread.sleep((int)(Math.random()*10)*100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

(4)编写消费者线程类(Consumer.java)

消费者与店员也有关系,所以店员类被当做属性引入进来,同样通过构造器完成初始化店员类对象的任务。

package SynchronizedThread;
//编写消费者线程类
public class Consumer implements Runnable {//消费者线程要执行的任务
private Clerk clerk;
public Consumer() {
super();
}
public Consumer(Clerk clerk) {
super();
this.clerk = clerk;
}
public void run() {
System.out.println("消费者开始取走产品");
for (int i = 0; i <15; i++) {//注意此处的循环次数一定要大于pro数组的长度(10)
//取产品
Products pd=clerk.getProduct();
System.out.println("消费了:"+pd);
try { //睡眠时间用随机产生的值来设置
Thread.sleep((int)(Math.random()*10)*100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

(5)编写生产者消费者问题的测试类( ProducerAndConsumerTest.java)

创建生产者和消费者线程,然后分别调度线程。

package SynchronizedThread;
//生产者消费者问题测试
public class ProducerAndConsumerTest {
public static void main(String[] args) {
Clerk clerk=new Clerk();
Thread producerThread=new Thread(new Producer(clerk));//创建生产者线程
Thread consumerThread=new Thread(new Consumer(clerk));//创建消费者线程
producerThread.start();
consumerThread.start();
}
}

(6)运行程序,在控制台得到的输出结果如下所示:

五、实验总结

1.本次实验按时按量完成。

2.线程和进程的区别:

在操作系统中能同时运行多个任务(程序)叫做多进程;在同一应用程序中多条执行路径并发执行叫做多线程。

(1)每个进程都有独立的代码和数据空间(进程上下文),进程间的切换开销大。

(2)同一进程内的多个线程共享相同的代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程间的切换开销小。

通常,在以下情况中可能要使用到多线程:

(1)程序需要同时执行两个或多个任务。

(2)程序需要实现一些需要等待的任务时,如用户输入、文件读写操作、网络操作、搜索等。

(3)需要一些后台运行的程序时。

3.线程同步的方法:为了共享区域的安全,可以通过关键字synchronized来加保护伞,以保证数据的安全。synchronized主要应用于同步代码块和同步方法中。

(1) 同步方法:synchronized放在方法声明中,表示整个方法为同步方法。

(2) 同步代码块:把线程体内执行的方法中会操作到共享数据的语句封装在{}之内,然后用synchronized放在某个对象前面修饰这个代码块。

如果一个线程调用了synchronized修饰的方法,它就能够保证该方法在执行完毕前不会被另一个线程打断,这种运行机制叫作同步线程机制。

4.在生产者线程类与消费者线程类中,设置让线程睡眠的时间如果是一样的,运行结果中会出现“生产一个消费一个,生产与消费时成对出现的“的这个不符合现实的现象。这时需要修改线程的睡眠时间,把睡眠时间用随机产生的值来设置。这样之后,再次运行程序,可以看到有时候生产了多个产品后,消费者才开始消费。

Normal
0

7.8 磅
0
2

false
false
false

EN-US
ZH-CN
X-NONE

MicrosoftInternetExplorer4

 

/* Style Definitions */
table.MsoNormalTable
{mso-style-name:普通表格;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-qformat:yes;
mso-style-parent:"";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin:0cm;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:10.5pt;
mso-bidi-font-size:11.0pt;
font-family:"Calibri","sans-serif";
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:宋体;
mso-fareast-theme-font:minor-fareast;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;
mso-font-kerning:1.0pt;}

Java 多线程程序设计的更多相关文章

  1. Java多线程程序设计详细解析

    一.理解多线程 多线程是这样一种机制,它允许在程序中并发执行多个指令流,每个指令流都称为一个线程,彼此间互相独立. 线程又称为轻量级进程,它和进程一样拥有独立的执行控制,由操作系统负责调度,区别在于线 ...

  2. Java多线程_复习(更新中!!)

    java多线程的常见例子 一.相关知识: Java多线程程序设计到的知识: (一)对同一个数量进行操作 (二)对同一个对象进行操作 (三)回调方法使用 (四)线程同步,死锁问题 (五)线程通信 等等 ...

  3. java多线程编程

    一.多线程的优缺点 多线程的优点: 1)资源利用率更好2)程序设计在某些情况下更简单3)程序响应更快 多线程的代价: 1)设计更复杂虽然有一些多线程应用程序比单线程的应用程序要简单,但其他的一般都更复 ...

  4. Java 多线程——基础知识

    java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...

  5. 从JAVA多线程理解到集群分布式和网络设计的浅析

    对于JAVA多线程的应用非常广泛,现在的系统没有多线程几乎什么也做不了,很多时候我们在何种场合如何应用多线程成为一种首先需要选择的问题,另外关于java多线程的知识也是非常的多,本文中先介绍和说明一些 ...

  6. 学习笔记之JAVA多线程

    Java程序设计实用教程 by 朱战立 & 沈伟 孙鑫Java无难事 Java 多线程与并发编程专题(http://www.ibm.com/developerworks/cn/java/j-c ...

  7. java多线程 并发 编程

    转自:http://www.cnblogs.com/luxiaoxun/p/3870265.html 一.多线程的优缺点 多线程的优点: 1)资源利用率更好 2)程序设计在某些情况下更简单 3)程序响 ...

  8. Java多线程编程中Future模式的详解

    Java多线程编程中,常用的多线程设计模式包括:Future模式.Master-Worker模式.Guarded Suspeionsion模式.不变模式和生产者-消费者模式等.这篇文章主要讲述Futu ...

  9. Java多线程与并发模型之锁

    这是一篇总结Java多线程开发的长文.文章是从Java创建之初就存在的synchronized关键字引入,对Java多线程和并发模型进行了探讨.希望通过此篇内容的解读能帮助Java开发者更好的理清Ja ...

随机推荐

  1. grunt 执行

    几天以前,我决定开始启用一个CSS预处理器,找了很久,我选择了SASS并且尝试着去安装它.但是这似乎不是一件简单的事,在安装过程中出现了许多让我始料不及的问题,我很沮丧,但查找了很多资料,我终于找到了 ...

  2. C++11 | 正则表达式(4)

    C++11还支持正则表达式里的子表达式(也叫分组),用sub_match这个类就行了. 举个简单的例子,比如有个字符串"/id:12345/ts:987697413/user:678254& ...

  3. 获取客户端ip并用正则表达式验证

    代理HTTP_VIA /// <summary> /// 获得请求的ip /// </summary> /// <returns></returns> ...

  4. 图像和滚动 、 编程规范和Xcode(一)

    1 在界面上以各种模式显示图片 1.1 问题 在ios开发中经常需要展示图片以满足需求和美化界面,本案例将学习如何以代码的方式使用UIImageView视图控件来展示图片,如图-1所示: 图-1 1. ...

  5. 在用的vim插件

    The-NERD-tree  https://github.com/vim-scripts/The-NERD-tree 在vim中也可以有目录树的,如果要打开当前文件夹下的其他文件的话也可以很方便的进 ...

  6. wrk中的lua脚本(转)

    转载地址:http://www.tuicool.com/articles/IFjIJjU wrk是一款现代化的http压测工具,提供lua脚本的功能可以满足每个请求或部分请求的差异化. wrk中执行h ...

  7. poj 3159 dijkstra 最短路

    Description During the kindergarten days, flymouse was the monitor of his class. Occasionally the he ...

  8. ZOJ 1074 To the Max

    原题链接 题目大意:这是一道好题.在<算法导论>这本书里面,有一节是介绍如何求最大子序列的.这道题有点类似,区别是从数组变成了矩阵,求最大子矩阵. 解法:完全没有算法功底的人当然不知道最大 ...

  9. android listview去掉分割线

    1:android listview去掉分割线 1>设置android:divider="@null" 2>android:divider="#0000000 ...

  10. Commons-Beanutils包详解

    Commons-Beanutils(一) Commons-Beanutils这个是jakarta commons项目中的一个子项目.这个项目开发的目的是帮助开发者动态的获取/设值Java Bean的属 ...