一、实验目的(结出本次实验所涉及并要求掌握的知识点)
1、理解掌握线程的基本概念。
2、理解和掌握Java多线程结构和开发过程。
3、了解多线程运行机制和生命周期及状态迁移。
4、学会如何创建线程,掌握线程的调度策略,线程优先级和线程同步。
二、实验内容(结出实验内容具体描述)
1.设计一个线程类,它能输出 50 以内的奇数或偶数。用书中介绍的四种构造线程方法,创建两个线程对象,分别输出奇数和偶数。
2. 给定容量 1000 的 int 型数组,依次存储数据 0~999。下面代码采用多线 程技术计算其累加和。
3. 功能:实现多人竞争打电话,借助互斥机制,确保每个人的说话是连续 的。 class DianHuaTing{//此类对象仅提供多人打电话的共享资源 private final String dht="我是电话亭"; } class App{ public static void main (String[] args) { DianHuaTing d=new DianHuaTing(); String[] s1={"1","2","3"}; String[] s2={"A","B","C","D","E"}; String[] s3={"你好,","我也好,","大家都好!"}; Talkers t1=new Talkers(d,"张三",s1); Talkers t2=new Talkers(d,"李四",s2); Talkers t3=new Talkers(d,"王五",s3); t1.start (); t2.start (); t3.start (); } }
4. 假设某个银行,它可以授受顾客的汇款,每做一次汇款,便可计算出汇 款的总额。现有两个顾客对同一个银行帐号操作,一个顾客分 3 次,每次 将 100 元钱存入,要求存入后将钱的总额输出。
5. 类 BufferArea 用于产生一个[1..100]的随机整数,并可取出此数。存数线 程类 ThreadPutNumber 将数存入缓冲区。读数线程类 ThreadPutNumber 从 缓冲区读取数并判断是否是素数。要求 main 线程最后结束。
三、算法描述及实验步骤(用适当的形式表达算法设计思想与算法实现步骤)
①小实验一:设计一个线程类,它能输出 50 以内的奇数或偶数。用书中介绍的四种构造线程方法,创建两个线程对象,分别输出奇数和偶数。
分析:线程要包括三大点:1、要有汽车Thread类,2、要有线程体void run() 3、要有共享资源.start()
四种方法包括继承Thread类方法;实现Runnable接口方法;内部类方法;内部匿名类方法。四种方法的共同点都是要实现run()函数,然后通过main()实现多线程的同时进行,注意。main是特殊线程,最先启动,且只有当所有线程均结束后才能结束;千万不要重写start(), 不要主动调用run()。
由分析和图示可得代码:
方法一:继承Thread类:
class MyThread extends Thread{
private int n,m;
public MyThread (String name,int n1,int m1) {
super(name);n=n1;m=m1;
}
public void run() {
for(int i=0;i<m;i++) {
if(i%2==n) {
System.out.print(i+" ");
}
}
System.out.println(getName()+"结束 ");
}
}
public class T1{
public static void main(String[] args) {
System.out.print("Main 开始");
MyThread m1=new MyThread("A",0,50);
MyThread m2=new MyThread("B",1,50);
m1.start();m2.start();
System.out.println("当前共有"+Thread.activeCount()+"个线程 ");
System.out.println("Main 结束");
}
}
方法二:实现Runnable接口:
class MyThread implements Runnable{
private int n,m;
public MyThread (int n1,int m1) {
n=n1;m=m1;
}
@Override
public void run() {
// TODO 自动生成的方法存根
for(int i=0;i<m;i++) {
if(i%2==n) {
System.out.print(i+" ");
}
}
System.out.println(Thread.currentThread().getName()+" 结束 ");
}
}
public class T2 {
public static void main(String[] args) {
System.out.print("Main 开始");
MyThread m1,m2;Thread t1,t2;
m1=new MyThread(0,50);
m2=new MyThread(1,50);
t1=new Thread(m1,"A");
t2=new Thread(m2,"B");
t1.start();t2.start();
System.out.println("当前共有"+Thread.activeCount()+"个线程 ");
System.out.println("Main 结束");
}
}
方法三:实现内部类:
class MyThread implements Runnable{
private int n,m;Thread t;
public MyThread(String name,int n1,int m1) {
n=n1;m=m1;t=new Thread(this,name);
}
public void start() {
t.start();
}
public void run() {
for(int i=0;i<m;i++) {
if(i%2==n) {
System.out.print(i+" ");
}
}
System.out.println(Thread.currentThread().getName()+" 结束 ");
}
}
public class T3 {
public static void main(String[] args) {
System.out.print("Main 开始");
MyThread m1,m2;
m1=new MyThread("A",0,50);
m2=new MyThread("B",1,50);
m1.start();m2.start();
System.out.println("当前共有"+Thread.activeCount()+"个线程 ");
System.out.println("Main 结束");
}
}
4.实现内部匿名类:
class T{
class MyThread extends Thread{
private int n,m;
public MyThread(String name,int n1,int m1) {
super(name); n=n1; m=m1;
}
public void run() {
for(int i=0;i<m;i++) {
if(i%2==n) {
System.out.print(i+" ");
}
}
System.out.println(getName()+"结束 ");
}
}
public T(String name,int n1,int m1) {
MyThread m=new MyThread(name,n1,m1);m.start();
}
}
public class T4 {
public static void main(String[] args) {
System.out.print("Main 开始"); T t1,t2;
t1=new T("A",0,50);
t2=new T("B",1,50);
System.out.println("当前共有"+Thread.activeCount()+"个线程");
System.out.print("Main 结束");
}
}
小实验2:给定容量 1000 的 int 型数组,依次存储数据 0~999。下面代码采用多线 程技术计算其累加和。
实验代码如下:
package jjk;
public class App {
public static void main(String[] args) throws InterruptedException {
final int max = 1000;
int[] a = new int[max];
int sum1 = 0, sum2 = 0, step = 10, num = 4;
//每个线程每次至多累加 10 个数,共有 4 个线程
for (int i = 0; i < max; i++) {//先计算出正确的累加和,以方便对比
a[i] = i;
sum1 = sum1 + a[i];
}
Pos p=new Pos(max,step);
sum2=SumByThread(p, a,num,step);
System.out.print("顺序:"+sum1+",并发:"+sum2);
}
public static int SumByThread(Pos p,int[] a,int num,int step) throws InterruptedException {
MyThread[] t = new MyThread[4];
for(int i=0;i<num;i++) {
t[i] = new MyThread(p,step,a);
t[i].start();
}
Thread.sleep(1000);
return MyThread.sum;
}
}
class Pos {
private int max, step,pos;
public Pos(int max,int step) {
this.max = max;
this.step = step;
pos = 0;
}
public int getPos() {
if(pos < max) {
return pos;
}
return -1;
}
public void setPos(int pos) {
this.pos = pos;
}
}
class MyThread extends Thread {
static int sum=0;
private int step;
private Pos p;
private int[] a;
private boolean flag;
public MyThread(Pos p,int step,int[] a) {
this.p = p;
this.step = step;
this.a = a;
flag = false;
}
public void run() {
while(true) {
for(int i=0;i<step;i++) {
synchronized (p) {
if(p.getPos() != -1) {
sum+=a[p.getPos()];
System.out.println(Thread.currentThread().getName()+" num:"+a[p.getPos()]+ " sum:"+sum);
p.setPos(p.getPos()+1);
} else {
return;
}
}
}
try {
this.wait();
this.notifyAll();
} catch (Exception e) {
}
}
}
小实验3: 功能:实现多人竞争打电话,借助互斥机制,确保每个人的说话是连续 的。 class DianHuaTing{//此类对象仅提供多人打电话的共享资源 private final String dht="我是电话亭"; } class App{ public static void main (String[] args) { DianHuaTing d=new DianHuaTing(); String[] s1={"1","2","3"}; String[] s2={"A","B","C","D","E"}; String[] s3={"你好,","我也好,","大家都好!"}; Talkers t1=new Talkers(d,"张三",s1); Talkers t2=new Talkers(d,"李四",s2); Talkers t3=new Talkers(d,"王五",s3); t1.start (); t2.start (); t3.start (); } }
分析:本题的难点在于互斥机制,即实现每个人说的话连续,这就需要使用synchronized(),synchronize具有三个特性(1)、原子性:所谓原子性就是指一个操作或者多个操作,要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。被synchronized修饰的类或对象的所有操作都是原子的,因为在执行操作之前必须先获得类或对象的锁,直到执行完才能释放。
(2)、可见性:可见性是指多个线程访问一个资源时,该资源的状态、值信息等对于其他线程都是可见的。 synchronized和volatile都具有可见性,其中synchronized对一个类或对象加锁时,一个线程如果要访问该类或对象必须先获得它的锁,而这个锁的状态对于其他任何线程都是可见的,并且在释放锁之前会将对变量的修改刷新到共享内存当中,保证资源变量的可见性。
(3)、有序性:有序性值程序执行的顺序按照代码先后执行。 synchronized和volatile都具有有序性,Java允许编译器和处理器对指令进行重排,但是指令重排并不会影响单线程的顺序,它影响的是多线程并发执行的顺序性。synchronized保证了每个时刻都只有一个线程访问同步代码块,也就确定了线程执行同步代码块是分先后顺序的,保证了有序性。
所以可以通过synchronize来实现互斥机制。
实验代码如下:
package e;
class DianHuaTing{//此类对象仅提供多人打电话的共享资源
private final String dht="我是电话亭";
}
class Talkers extends Thread{
private DianHuaTing dianhuating;
private String name;
private String[] content;
public Talkers(DianHuaTing f,String n,String[] s) {
dianhuating=f;name=n;content=s;
}
public void run() {
synchronized(dianhuating) {
System.out.print(name+" : ");
for(String x:content) System.out.print(" "+x);
System.out.println();
}
}
}
class App{
public static void main (String[] args) {
DianHuaTing d=new DianHuaTing();
String[] s1={"1","2","3"};
String[] s2={"A","B","C","D","E"};
String[] s3={"你好,","我也好,","大家都好!"};
Talkers t1=new Talkers(d,"张三",s1);
Talkers t2=new Talkers(d,"李四",s2);
Talkers t3=new Talkers(d,"王五",s3);
t1.start (); t2.start (); t3.start ();
}
}
小实验4:假设某个银行,它可以授受顾客的汇款,每做一次汇款,便可计算出汇 款的总额。现有两个顾客对同一个银行帐号操作,一个顾客分 3 次,每次 将 100 元钱存入,要求存入后将钱的总额输出。
分析: 实现这个程序,同样也要用到互斥机制,同时还要用到join(),以保证前面执行完成后再执行后面的内容而不造成混乱。
实验代码如下:
class Account{
private String name;
private double value;
public String getName() {return name;}
public double getValue() {return value;}
public Account(String s,int d) {
name=s;value=d;
}
public void putV(double m) {
value+=m;
}
public void getV(double p) {
value-=p;
}
}
class Saver extends Thread{
private Account a;
private int i;
public double c;
public String nam;
public Saver(Account a1,String n,int i,double c1) {
a=a1;
nam=n;
this.i=i;
c=c1;
}
public void run() {
synchronized (a) {
try {
sleep(100);
} catch (InterruptedException e1) {
// TODO 自动生成的 catch 块
e1.printStackTrace();
}
System.out.println("银行当前余额为"+a.getValue()+","+nam+"第"+i+"次存入"+c+"元");
try {
sleep(100);
} catch (InterruptedException e1) {
// TODO 自动生成的 catch 块
e1.printStackTrace();
}
a.putV(c);
try {
sleep(100);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
System.out.println("当前银行余额为:"+a.getValue());
try {
sleep(100);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
}
class Fetcher extends Thread{
private Account a;
private int i;
public double c;
public String nam;
public Fetcher(Account a1,String n,int i,double c1) {
a=a1;
nam=n;
this.i=i;
c=c1;
}
public void run() {
synchronized (a) {
System.out.println("银行当前余额为"+a.getValue()+","+nam+"第"+i+"次取出"+c+"元");
a.getV(c);
System.out.println("当前银行余额为:"+a.getValue());
}
}
}
public class App {
public static void main(String[] args) throws InterruptedException {
Account a=new Account("刘",1000);
/*Saver s1=new Saver(a,"aa",1,100);s1.start();
try {
s1.join();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
Saver s2=new Saver(a,"bb",1,100);s2.start();
try {
s2.join();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
Saver s3=new Saver(a,"aa",2,100);s3.start();
try {
s3.join();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
Saver s4=new Saver(a,"bb",2,100);s4.start();
try {
s4.join();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
Saver s5=new Saver(a,"aa",3,100);s5.start();
Saver s6=new Saver(a,"bb",3,100);s6.start();*/
//(new Fetcher(a,300)).start();
Saver s1=new Saver(a,"aa",1,100);s1.start();
s1.join();
Saver s2=new Saver(a,"bb",1,100);s2.start();
s2.join();
Saver s3=new Saver(a,"aa",2,100);s3.start();
s3.join();
Saver s4=new Saver(a,"bb",2,100);s4.start();
s4.join();
Saver s5=new Saver(a,"aa",3,100);s5.start();
s5.join();
Saver s6=new Saver(a,"bb",3,100);s6.start();
}
}
实验5:类 BufferArea 用于产生一个[1..100]的随机整数,并可取出此数。存数线 程类 ThreadPutNumber 将数存入缓冲区。读数线程类 ThreadPutNumber 从 缓冲区读取数并判断是否是素数。要求 main 线程最后结束。
分析: 这个程序类似于生产者和消费者的问题,首先通过缓冲区生产随机数,然后生产者put出来,接着消费者用get方法获得这个数字,同时进行判别是否为素数即可。
由分析可得代码如下:
class BufferArea{//缓冲区
public int d;
private boolean isEmpty=true;
public synchronized void put(int i) {
while(!isEmpty)
try {wait();}catch(InterruptedException e) {;}
d=i;isEmpty=false;notify();
}
public synchronized int get() {
while(isEmpty)try {wait();}catch(InterruptedException e) {;}
isEmpty=true;notify();
return d;
}
}
class ThreadPutNumber extends Thread{
private BufferArea ba;int z;
public ThreadPutNumber(BufferArea b) {ba=b;}
private int[] a=new int[100];
public void run() {
for(z=0;z<a.length;z++) {
a[z]=(int)(Math.random()*100+1);
ba.put(a[z]);
}
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class ThreadGetNumber extends Thread{
private BufferArea ba;
ThreadPutNumber t;
private boolean flag =true;
public ThreadGetNumber (BufferArea b) {ba=b;}
public void run() {
for (int j = 1; j<6; j++){
int num=ba.get();
System.out.print("put number is:"+num+"\t");
for(int i=2;i<num-1;i++) {
if(num%2==0) {
flag=false;
}
}
if(flag) {
System.out.println(num+"is a prime!");
}
else {
System.out.println(num+"is not a prime!");
}
}
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class App {
public static void main(String[] args) throws InterruptedException {
BufferArea b=new BufferArea();
ThreadGetNumber t1=new ThreadGetNumber(b); t1.start();
(new ThreadPutNumber(b)).start();
t1.join();
System.out.println("Main is over!");
}
}
四、调试过程及运行结果(详细记录在调试过程中出现的问题及解决方法。记录实验执行的结果)
①小实验1:设计一个线程类,它能输出 50 以内的奇数或偶数。用书中介绍的四种构造线程方法,创建两个线程对象,分别输出奇数和偶数。

②小实验2:给定容量 1000 的 int 型数组,依次存储数据 0~999。下面代码采用多线程技术计算其累加和。

③小实验3:功能:实现多人竞争打电话,借助互斥机制,确保每个人的说话是连续 的。 class DianHuaTing{//此类对象仅提供多人打电话的共享资源 private final String dht="我是电话亭"; } class App{ public static void main (String[] args) { DianHuaTing d=new DianHuaTing(); String[] s1={"1","2","3"}; String[] s2={"A","B","C","D","E"}; String[] s3={"你好,","我也好,","大家都好!"}; Talkers t1=new Talkers(d,"张三",s1); Talkers t2=new Talkers(d,"李四",s2); Talkers t3=new Talkers(d,"王五",s3); t1.start (); t2.start (); t3.start (); } }

④小实验4:假设某个银行,它可以授受顾客的汇款,每做一次汇款,便可计算出汇 款的总额。现有两个顾客对同一个银行帐号操作,一个顾客分 3 次,每次 将 100 元钱存入,要求存入后将钱的总额输出。

⑤小实验5:类 BufferArea 用于产生一个[1..100]的随机整数,并可取出此数。存数线 程类 ThreadPutNumber 将数存入缓冲区。读数线程类 ThreadPutNumber 从 缓冲区读取数并判断是否是素数。要求 main 线程最后结束。

&spm=1001.2101.3001.5002&articleId=131051217&d=1&t=3&u=339de00a08c24d5d94788b712ca65db0)
4135

被折叠的 条评论
为什么被折叠?



