(1)掌握Java多线程的概念和实现
(2)掌握Java多线程的同步问题
(3)掌握集合框架的知识,学会使用Arraylist<E>,LinkedList<E>和HashMap<K,V>类, HashSet<E>类。
2.实验要求
在Eclipse下创建Practice5项目,对未有包名要求的题目统一按照实验题名建包,然后将本题源代码 放在同一包下。对有包名要求的题目按照要求建包。作业提交时将Practice5项目下src文件包命名为Practice5.src压缩后提交。
3.实验题目
Exer1: 假设我们赋予每个线程一个唯一的编号,每次线程运行时打印其编号10次。定义测试类,在测试类中创建3个上述线程,并调用start()方法开始运行,观察运行结果;如果每个线程中的迭代次数增加至100次,观察结果,理解线程的并发处理;如果调用方法改为run(),运行结果会变化吗?
package Exer1;
public class print extends Thread {
public void run() {
for(int i =1;i<=100;i++) {
System.out.println("打印编号"+Thread.currentThread().getName()+"第"+i+"次。");
}
}
}
package Exer1;
public class Exer1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
print print1 = new print();
print print2 = new print();
print print3 = new print();
print1.setName("一");
print2.setName("二");
print3.setName("三");
print1.start();
print2.start();
print3.start();
}
}
编译运行
Exer2:完成 P394编程题(1)。
package Exer2;
public class TicketHouse implements Runnable{
int fiveAmount = 3,tenAmount=0,twentyAmount = 0;
public void run() {
if(Thread.currentThread().getName().equals("张某")) {
salesTicket(20);
}
else if(Thread.currentThread().getName().equals("李某")) {
salesTicket(10);
}
else if(Thread.currentThread().getName().equals("赵某")) {
salesTicket(5);
}
}
private synchronized void salesTicket(int money) {
if(money == 5) {
fiveAmount = fiveAmount+1;
System.out.println("给"+Thread.currentThread().getName()+"入场券,"+Thread.currentThread().getName()+"的钱正好");
}
else if(money == 10) {
while(fiveAmount<1) {
try {System.out.println("\n"+Thread.currentThread().getName()+"靠边等...");
wait();
System.out.println("\n"+Thread.currentThread().getName()+"继续买票");
}
catch(InterruptedException e) {}
}
fiveAmount = fiveAmount-1;
tenAmount = tenAmount+1;
System.out.println("给"+Thread.currentThread().getName()+"入场券,"+Thread.currentThread().getName()+
"给10元,找赎5元");
}else if(money == 20) {
while(fiveAmount<3) {
try {System.out.println("\n"+Thread.currentThread().getName()+"靠边等...");
wait();
System.out.println("\n"+Thread.currentThread().getName()+"继续买票");
}
catch(InterruptedException e) {}
}
fiveAmount = fiveAmount-3;
twentyAmount = twentyAmount+1;
System.out.println("给"+Thread.currentThread().getName()+"入场券,"+Thread.currentThread().getName()+
"给20元,找赎15元");
}
notifyAll();
}
}
package Exer2;
public class Exer2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
TicketHouse officer = new TicketHouse();
Thread zhang,li,zhao;
zhang = new Thread(officer);
zhang.setName("张某");
li = new Thread(officer);
li.setName("李某");
zhao = new Thread(officer);
zhao.setName("赵某");
zhang.start();
li.start();
zhao.start();
}
}
编译运行
第一次运行
第二次运行
Exer3: 有一个关于Product类型的数组(货架),数组容量为16。生产者往货架上放置商品,消费者从货架上购买商品。二者是并发执行的。(货架空的时候只能生产,货架满的时候只能消费。)使用多线程并发机制,模拟商品编号从1到100的生产和消费过程。
要求:
只模拟一个生产者和一个消费者的情况;
package Exer3;
//销售
public class Customer implements Runnable{
private Goods goods;
int sl= 0;
public Customer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
while(true) {
synchronized(goods) {
if(goods.getGoodsNum()>0 && sl<100) {
int saleNum = goods.saleGoods();//销售货物
sl = sl + saleNum;
System.out.println("销售中......销售了"+saleNum+" 当前货物数量:"+goods.getGoodsNum()
+ " 已销售" + sl );
}
}
//2次销售之间的时间随机生成,但不大于2s。
try {
int time = (int)(Math.random()*20+1);
Thread.sleep(time);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
package Exer3;
//商品类
public class Goods {
int goodsNum = 0;//商品数目
int sc = 0;
//进货,并返回进货数量
public int addGoods() {
int addNum = (int)(Math.random()*(16-goodsNum)+1); //生产数量不大于货架容量16
sc = sc +addNum;
goodsNum +=addNum;
if(sc>100) {
sc -= addNum;
goodsNum -= addNum;
addNum = 100 - sc;
goodsNum += addNum;
sc += addNum;
}
return addNum;
}
//销售,并返回销售数量
public int saleGoods() {
int saleNum = (int)(Math.random()*this.goodsNum+1);//销售数量不大于商品数量
goodsNum -= saleNum;
return saleNum;
}
public int getGoodsNum() {
return goodsNum;
}
public void setGoodsNum(int goodsNum) {
this.goodsNum = goodsNum;
}
}
package Exer3;
public class Producer implements Runnable{
private Goods goods;
public Producer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
while(true) {
synchronized(goods) {
if(goods.getGoodsNum()<=0 && goods.sc<=100) {
int addNum = goods.addGoods();//生产货物
System.out.println("生产中......生产了"+addNum+" 当前货物数量为:"+goods.getGoodsNum()
+" 已生产"+goods.sc);
if (goods.sc == 100) {
break;
}
}
}
}
}
}
package Exer3;
public class Exer3 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Goods goods = new Goods(); //销售和进货共用一个商品对象
Thread t1 = new Thread(new Customer(goods));
Thread t2 = new Thread(new Producer(goods));
t1.start();
t2.start();
}
}
编译运行
生产中......生产了11 当前货物数量为:11 已生产11
销售中......销售了10 当前货物数量:1 已销售10
销售中......销售了1 当前货物数量:0 已销售11
生产中......生产了3 当前货物数量为:3 已生产14
销售中......销售了3 当前货物数量:0 已销售14
生产中......生产了3 当前货物数量为:3 已生产17
销售中......销售了2 当前货物数量:1 已销售16
销售中......销售了1 当前货物数量:0 已销售17
生产中......生产了7 当前货物数量为:7 已生产24
销售中......销售了4 当前货物数量:3 已销售21
销售中......销售了3 当前货物数量:0 已销售24
生产中......生产了2 当前货物数量为:2 已生产26
销售中......销售了1 当前货物数量:1 已销售25
销售中......销售了1 当前货物数量:0 已销售26
生产中......生产了16 当前货物数量为:16 已生产42
销售中......销售了6 当前货物数量:10 已销售32
销售中......销售了8 当前货物数量:2 已销售40
销售中......销售了2 当前货物数量:0 已销售42
生产中......生产了14 当前货物数量为:14 已生产56
销售中......销售了10 当前货物数量:4 已销售52
销售中......销售了1 当前货物数量:3 已销售53
销售中......销售了1 当前货物数量:2 已销售54
销售中......销售了1 当前货物数量:1 已销售55
销售中......销售了1 当前货物数量:0 已销售56
生产中......生产了14 当前货物数量为:14 已生产70
销售中......销售了3 当前货物数量:11 已销售59
销售中......销售了11 当前货物数量:0 已销售70
生产中......生产了10 当前货物数量为:10 已生产80
销售中......销售了7 当前货物数量:3 已销售77
销售中......销售了3 当前货物数量:0 已销售80
生产中......生产了15 当前货物数量为:15 已生产95
销售中......销售了13 当前货物数量:2 已销售93
销售中......销售了1 当前货物数量:1 已销售94
销售中......销售了1 当前货物数量:0 已销售95
生产中......生产了5 当前货物数量为:5 已生产100
销售中......销售了3 当前货物数量:2 已销售98
销售中......销售了2 当前货物数量:0 已销售100
集合框架
Exer4:用LinkedList或ArrayList存放对象
- 利用面向对象的思想,创建以下类:
- Person类,包含Person的姓名和身份证号码,覆盖Object类的toString()方法,显示“姓名:XXX 身份证号:XXX”。
- Student类,继承Person类,包含学生的语文、数学、英文课的成绩,并覆盖父类的toString()方法,显示“姓名:XXX 身份证号:XXX 语文:XXX 数学:XXX 英文:XXX”。
- Teacher类,继承Person类,包含教师的工资。并覆盖父类的toString()方法,显示“姓名:XXX 身份证号:XXX 工资:XXX”。
- 分别为以上三个类创建对象:
Person对象 | Student对象 | Teacher对象 |
姓名:张三 | 姓名:李四 | 姓名:王五 |
身份证号:12310001 | 身份证号:12320002 | 身份证号:12330003 |
语文: 89 | 工资:4000 | |
数学: 93 | ||
英文: 94 |
- 将这三个对象存放在一个LinkedList或ArrayList对象中:
LinkedList<Person> list=new LinkedList<Person>();
或
ArrayList<Person> list=new ArrayList<Person>();
- 运行示例:
- 练习使用LinkedList的其他方法。将自己的信息添加到链表的开头,以及结尾,然后再删除自己的信息。
返回类型 | 方法名称 | 描述 |
void | addFirst() | 将指定元素插入此列表的开头 |
void | addLast() | 将指定元素添加到此列表的结尾 |
E | removeFirst() | 移除并返回此列表的第一个元素 |
E | removeLast() | 移除并返回此列表的最后一个元素 |
boolean | add(Object o) | 将指定的元素添加到列表中 |
package Exer4;
class Person {
String name;
String ID;
Person(String name,String ID){
this.name = name;
this.ID = ID;
}
public String toString() {
return "姓名:" + name + " 身份证号:" + ID;
}
}
package Exer4;
public class Teacher extends Person{
int wages;
Teacher(String name,String ID,int wages){
super(name,ID);
this.wages = wages;
}
public String toString() {
return "姓名:" + name + " 身份证号:" + ID + " 工资:"+wages;
}
}
package Exer4;
public class Student extends Person{
int yuwen,shuxue,yingwen;
Student(String name,String ID,int yuwen,int shuxue,int yingwen){
super(name,ID);
this.yuwen = yuwen;
this.shuxue = shuxue;
this.yingwen = yingwen;
}
public String toString() {
return "姓名:" + name + " 身份证号:" + ID+" 语文:"+yuwen
+ " 数学:" + shuxue + " 英文:" + yingwen;
}
}
package Exer4;
import java.util.*;
public class Exer4 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Person person = new Person("张三","12310001");
Student student = new Student("李四","12320002",89,93,94);
Teacher teacher = new Teacher("王五","12330003",4000);
LinkedList<Person> list=new LinkedList<Person>();
list.add(person);
list.add(student);
list.add(teacher);
Person p1 = list.get(0);
Person p2 = list.get(1);
System.out.println(p1.toString());
System.out.println(p2.toString());
System.out.println();
Person student1 = new Student("艾莎女王","11111111",100,100,100);
list.addFirst(student1); //将自己的信息添加到链表的开头
list.addLast(student1); //将自己的信息添加到链表的结尾
p1 = list.getFirst();
p2 = list.getLast();
for (int i =0;i<list.size();i++) {
Person pp = list.get(i);
System.out.println(pp.toString());
}
System.out.println();
Person p3 = list.removeFirst();
Person p4 = list.removeLast();
Iterator<Person> iter = list.iterator();
while(iter.hasNext()) {
Person pp = iter.next();
System.out.println(pp.toString());
}
}
}
编译运行
姓名:张三 身份证号:12310001
姓名:李四 身份证号:12320002 语文:89 数学:93 英文:94
姓名:艾莎女王 身份证号:11111111 语文:100 数学:100 英文:100
姓名:张三 身份证号:12310001
姓名:李四 身份证号:12320002 语文:89 数学:93 英文:94
姓名:王五 身份证号:12330003 工资:4000
姓名:艾莎女王 身份证号:11111111 语文:100 数学:100 英文:100
姓名:张三 身份证号:12310001
姓名:李四 身份证号:12320002 语文:89 数学:93 英文:94
姓名:王五 身份证号:12330003 工资:4000
Exer5:用SET存放对象
- 将以下三个Person类的对象放在一个HashSet中,由于HashSet不能存放重复的元素(姓名和身份证号都不能重复),所以在Person类中,需要覆盖hashCode()方法和equals()方法。这里给出重写方法的程序:
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (id != other.id)
return false;
return true;
}
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + id;
return result;
}
Person对象 | Person对象 | Person对象 |
姓名:张三 | 姓名:李四 | 姓名:王五 |
身份证号:12310001 | 身份证号:12320002 | 身份证号:12330003 |
再创建一个Person对象:
Person对象 |
姓名:王五 |
身份证号:12330003 |
能放入到刚才创建的HashSet中吗?通过这个对象来测试hashCode()方法和equals()方法的编写是否正确。
- 把集合中的元素打印出来(使用迭代器Iterator类)。
- 用TreeSet存放上面三个人,要求按照身份证号排序,打印出来。(注意使用TreeSet要实现Comparable接口,并覆盖compareTo()方法)
package Exer5;
import java.util.*;
class Person implements Comparable {
String name;
int id;
public Person(String name,int ID){
this.name = name;
id = ID;
}
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (id != other.id)
return false;
return true;
}
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + id;
return result;
}
public int compareTo(Object b) {
Person st = (Person)b;
return (this.id - st.id);
}
}
package Exer5;
import java.util.*;
public class Exer5 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Person p1 = new Person("张三",12310001);
Person p2 = new Person("李四",12320002);
Person p3 = new Person("王五",12330003);
HashSet<Person> sites = new HashSet<Person>();
boolean a = sites.add(p1);
boolean b = sites.add(p2);
boolean c = sites.add(p3);
System.out.println(a+" "+ b + " " +c);
Person p4 = new Person("王五",12330003);
System.out.println( sites.add(p4)); //如果添加成功,返回true,否则返回false
TreeSet<Person> mytree = new TreeSet<Person>();
mytree.add(p1);
mytree.add(p2);
mytree.add(p3);
Iterator<Person> te = mytree.iterator();
while(te.hasNext()) {
Person per = te.next();
System.out.println(per.name + " " +per.id);
}
}
}
编译运行
true true true
false
张三 12310001
李四 12320002
王五 12330003