JAVA300第十一章多线程技术作业

一、 选择题

1.以下选项中可以填写到横线处,让代码正确编译和运行的是(AD)。

public class Test implements Runnable {
    public static void main(String[] args) {
        ___________________________________
        t.start();
        System.out.println("main");
    }
    public void run() {
        System.out.println("thread1!");
    }
}

A.Thread t = new Thread(new Test());

B.Test t = new Test();

C.Thread t = new Test();

D.Thread t = new Thread();

A:显示main thread1
D:显示main

2.当线程调用start( )后,其所处状态为( C)。

A.阻塞状态

B.运行状态

C.就绪状态

D.新建状态

3.以下选项中关于Java中线程控制方法的说法正确的是(AD)。

A.t.join ( ) 的作用是阻塞指定线程等到另一个线程完成以后再继续执行

B.sleep ( ) 的作用是让当前正在执行线程暂停,线程将转入就绪状态

C.yield ( ) 的作用是使线程停止运行一段时间,将处于阻塞状态

D.setDaemon( )的作用是将指定的线程设置成后台线程

B:执行sleep(int millsecond)方法,使当前线程休眠,进入阻塞状态。当指定的时间到了后,线程进入就绪状态。
C: yield()方法:可以让正在运行的线程直接进入就绪状态,让出CPU的使用权。

4.Java中线程安全问题是通过关键字( C)解决的。

A.finally

B.wait( )

C.synchronized

D.notify( )

5.以下说法中关于线程通信的说法错误的是(D)。

A.可以调用wait()、notify()、notifyAll()三个方法实现线程通信

B.wait()、notify()、notifyAll()必须在synchronized方法或者代码块中使用

C.wait()有多个重载的方法,可以指定等待的时间

D.wait()、notify()、notifyAll()是Object类提供的方法,子类可以重写

wait()、notify()、notifyAll()均由final修饰,子类不能重写

二、 简答题

1. 简述程序、进程和线程的联系和区别。

程序是一组指令的集合,它是静态的实体,没有执行的含义。而进程是一个动态的实体,有自己的生命周期。一般说来,一个进程肯定与一个程序相对应,并且只有一个,但是一个程序可以有多个进程,或者一个进程都没有。除此之外,进程还有并发性和交往性。简单地说,进程是程序的一部分,程序运行的时候会产生进程。

区别进程线程
根本区别作为资源分配的单位调度和执行的单位
开销每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销线程可以看作是轻量级的进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换的开销小
所处环境在操作系统中能够同时运行多个任务(程序)在同一应用程序中有多个顺序流同时执行
分配内存系统在运行的时候会为每个进程分配不同的内存区域系统在运行的时候不会为线程分配内存(线程所使用的资源是它所属的进程的资源),线程组只能共享资源。那就是说,除了CPU之外(线程在运行的时候要占用CPU资源),计算机内部的软硬件资源的分配与线程无关,线程只能共享它所属进程的资源。
包含关系没有线程的进程是可以被看作单线程的,如果一个进程拥有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成线程是进程的一部分,所以线程有的时候被称作为轻权线程或者轻量级线程。

2. 创建线程的两种方式分别是什么?各有什么优缺点。

共有三种方法:

  1. 继承Thread类
  2. 实现Runnable接口(多用接口)(方便共享资源)
  3. 实现Callable接口(不重要)与 Runnable 相比,Callable 可以有返回值

实现 Runnable 和 Callable 接口的类只能当做一个可以在线程中运行的任务,不是真正意义上的线程,因此最后还需要通过 Thread 来调用。可以说任务是通过线程驱动从而执行的。

  • Java 不支持多重继承,因此继承了 Thread 类就无法继承其它类,但是可以实现多个接口;
  • 类可能只要求可执行就行,继承整个 Thread 类开销过大。

3. sleep、yield、join方法的区别?

  1. sleep()方法:可以让正在运行的线程进入阻塞状态,直到休眠时间满了,进入就绪状态。
  2. yield()方法:可以让正在运行的线程直接进入就绪状态,让出CPU的使用权。
  3. join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞,你写在哪个线程体中,哪个线程体就阻塞了。

4. synchronize修饰的语句块,如下面的代码。是表示该代码块运行时必须获得account对象的锁。如果没有获得,会有什么情况发生?

synchronized (account) {
    if(account.money-drawingNum<0){
        return;
    }
}

会导致线程不安全,数据不准确

5. Java中实现线程通信的三个方法及其作用。

  1. wait():导致当前线程等待,直到其他线程调用该同步监视器的notify()方法或notifyAll()方法来唤醒该线程。
  2. notify():唤醒在此同步监视器上等待的单个线程。
  3. notifyAll():唤醒在此同步监视器上等待的所有线程。

三、 编码题

  1. 设计一个多线程的程序如下:设计一个火车售票模拟程序。假如火车站要有100张火车票要卖出,现在有5个售票点同时售票,用5个线程模拟这5个售票点的售票情况。
package week11_homework;

/**
 * 火车售票模拟程序
 * 
 * @author Jeloys
 *
 */
public class TrainTicket {
	public static void main(String[] args) {
		TrainStation station = new TrainStation();
		new Thread(station,"售票点1").start();
		new Thread(station,"售票点2").start();
		new Thread(station,"售票点3").start();
		new Thread(station,"售票点4").start();
		new Thread(station,"售票点5").start();
	}
}

//火车站
class TrainStation implements Runnable {
	private int ticketNums = 100;
	private boolean hasTickets = true;


	public void run() {
		while (hasTickets) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			orderTicket();
		}
	}
	
	public  void orderTicket() {
		if(ticketNums<=0) {//考虑的是没有票的情况
			hasTickets = false;
			return ;
		}
		synchronized(this) {			
			if(ticketNums<=0) {//考虑最后的1张票
				hasTickets = false;
				return ;
			}
			//模拟延时
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+"-->"+ticketNums--);
		}
	}
}
  1. 编写两个线程,一个线程打印1-52的整数,另一个线程打印字母A-Z。打印顺序为12A34B56C….5152Z。即按照整数和字母的顺序从小到大打印,并且每打印两个整数后,打印一个字母,交替循环打印,直到打印到整数52和字母Z结束。

    要求:

    1. 编写打印类Printer,声明私有属性index,初始值为1,用来表示是第几次打印。

    2. 在打印类Printer中编写打印数字的方法print(int i),3的倍数就使用wait()方法等待,否则就输出i,使用notifyAll()进行唤醒其它线程。

    3. 在打印类Printer中编写打印字母的方法print(char c),不是3的倍数就等待,否则就打印输出字母c,使用notifyAll()进行唤醒其它线程。

    4. 编写打印数字的线程NumberPrinter继承Thread类,声明私有属性private Printer p;在构造方法中进行赋值,实现父类的run方法,调用Printer类中的输出数字的方法。

    5. 编写打印字母的线程LetterPrinter继承Thread类,声明私有属性private Printer p;在构造方法中进行赋值,实现父类的run方法,调用Printer类中的输出字母的方法。

    6. 编写测试类Test,创建打印类对象,创建两个线程类对象,启动线程。

package week11_homework;

public class Printer {

	private int index = 1;

	public synchronized void print(int i) {
		// 在打印类Printer中编写打印数字的方法print(int i),3的倍数就使用wait()方法等待,
		// 否则就输出i,使用notifyAll()进行唤醒其它线程。
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		// 判断index是否能被3整除
		while (index % 3 == 0) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		System.out.println(i);
		index++;
		// 唤醒字母线程
		this.notifyAll();
	}

	public synchronized void print(char c) {
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		// 判断index是否不能被3整除
		while (index % 3 != 0) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		System.err.println(c);
		index++;
		// 唤醒其他线程
		this.notifyAll();
	}

	public Printer(int index) {
		super();
		this.index = index;
	}

	public Printer() {
		super();
	}
}
package week11_homework;

public class NumberPrinter extends Thread {

	private Printer p;

	public NumberPrinter(Printer p) {
		super();
		this.p = p;
	}

	@Override
	public void run() {
		// 调用Printer类中的输出数字的方法。
		for (int i = 1; i <= 52; i++) {
			p.print(i);
		}
	}

}
package week11_homework;

public class LetterPrinter extends Thread {
	private Printer p;

	public LetterPrinter(Printer p) {
		super();
		this.p = p;
	}
	
	@Override
	public void run() {
		for(char c ='A';c<='Z';c++){
			p.print(c);
		}
	}
}

package week11_homework;

public class PrinterTest {
	public static void main(String[] args) {
		Printer printer = new Printer();
		new Thread(new NumberPrinter(printer)).start();
		new Thread(new LetterPrinter(printer)).start();
	}
}
  1. 编写多线程程序,模拟多个人通过一个山洞的模拟。这个山洞每次只能通过一个人,每个人通过山洞的时间为5秒,有10个人同时准备过此山洞,显示每次通过山洞人的姓名和顺序。
package week11_homework;
public class CrossCave {
	public static void main(String[] args) {
		Cave cave = new Cave();
		new Thread(cave,"小赵").start();
		new Thread(cave,"小钱").start();
		new Thread(cave,"小孙").start();
		new Thread(cave,"小李").start();
		new Thread(cave,"小周").start();
		new Thread(cave,"小吴").start();
		new Thread(cave,"小郑").start();
		new Thread(cave,"小王").start();
		new Thread(cave,"小冯").start();
		new Thread(cave,"小陈").start();
		
	}
}

class Cave implements Runnable {
	private int count = 1;
	@Override
	public void run() {
		synchronized (this) {
				System.out.println(Thread.currentThread().getName() + "正在第"+ count++ +"个过山洞");	
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
	}

}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值