编程题
1、设计4个线程对象,其中两个线程执行减操作,另外两个线程执行减操作。
public class Resource { //定义一个操作的资源
private int num=0;// 进行加减操作的数据
private boolean flag=true; //加减的切换
//flag=true ,//表示可以进行加法操作,但无法进行减法操作。
//flag=false,//表示可以进行减法操作,但无法进行加法操作。
public synchronized void add() throws InterruptedException { //执行加法操作
if (this.flag==false) { //现在需要进行的是减法操作,加法操作需要等待
super.wait();
}
Thread.sleep(100);
this.num++;
System.out.println("加法操作 "+Thread.currentThread().getName()+" num="+this.num);
this.flag=false;//加法操作执行完毕,需要执行减法操作
super.notifyAll();//唤醒全部等待线程
}
public synchronized void sub() throws InterruptedException { //执行减法操作
if (this.flag==true) {//现在需要进行加法操作,减法操作需要等待
super.wait();
}
Thread.sleep(200);
this.num--;
System.out.println("减法操作 "+Thread.currentThread().getName()+" num="+this.num);
this.flag=true;//减法操作执行完毕,需要执行加法操作
super.notifyAll();//唤醒全部等待线程
}
}
public class AddThread implements Runnable {
private Resource resource;
public AddThread(Resource resource) {
this.resource = resource;
}
@Override
public void run() {
for (int x = 0; x < 50; x++) {
try {
this.resource.add();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class SubThread implements Runnable {
private Resource resource;
public SubThread(Resource resource) {
this.resource = resource;
}
@Override
public void run() {
for (int x = 0; x < 50; x++) {
try {
this.resource.sub();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class Thread01 {
public static void main(String[] args) {
Resource res=new Resource ();
AddThread at=new AddThread(res);
SubThread st=new SubThread(res);
new Thread(at,"加法线程-A").start();
new Thread(at,"加法线程-B").start();
new Thread(st,"减法线程-X").start();
new Thread(st,"减法线程-Y").start();
}
}
执行结果(部分)
减法操作 减法线程-X num=0
加法操作 加法线程-B num=1
减法操作 减法线程-X num=0
加法操作 加法线程-B num=1
减法操作 减法线程-X num=0
加法操作 加法线程-B num=1
减法操作 减法线程-X num=0
加法操作 加法线程-B num=1
减法操作 减法线程-X num=0
加法操作 加法线程-B num=1
减法操作 减法线程-X num=0
加法操作 加法线程-B num=1
减法操作 减法线程-X num=0
2、设计一个生产计算机和搬运计算机类,要求生产出一台计算机就搬走一台计算机,如果没有新的计算机生产出来,则搬运工要等待新计算机产出;如果生产出的计算机没有搬走,则要等待计算机搬走后在生产,并统计生产的计算机数量。
public class Computer {
private static int count=0;//表示生产的个数
private String name;
private double price;
public Computer(String name, double price) {
this.name = name;
this.price = price;
this.count++;
}
@Override
public String toString() {
return "【第"+count+"台电脑】电脑名称=" +this.name + ",电脑价格"+this.price;
}
}
public class Resource02 {
private Computer computer;
public synchronized void make() throws InterruptedException {
if(computer!=null) {//已经生产过了
super.wait();
}
Thread.sleep(100);
this.computer=new Computer("联想",5600.2);
System.out.println("生产电脑"+this.computer);
super.notifyAll();
}
public synchronized void get() throws InterruptedException {
if(computer==null) {
super.wait();
}
Thread.sleep(20);
System.out.println("取走电脑"+this.computer);
this.computer=null; //已经取走了
super.notifyAll();
}
}
public class Produce implements Runnable {
private Resource02 res;
public Produce(Resource02 res) {
this.res = res;
}
@Override
public void run() {
for (int x = 0; x < 50; x++) {
try {
this.res.make();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class Comuser implements Runnable {
private Resource02 res;
public Comuser(Resource02 res) {
this.res = res;
}
@Override
public void run() {
for (int x = 0; x < 50; x++) {
try {
this.res.get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class Thread02 {
public static void main(String[] args) {
Resource02 res=new Resource02();
Produce mk=new Produce(res);
Comuser ge=new Comuser(res);
new Thread(mk).start();
new Thread(ge).start();
}
}
执行结果(部分)
生产电脑【第28台电脑】电脑名称=联想,电脑价格5600.2
取走电脑【第28台电脑】电脑名称=联想,电脑价格5600.2
生产电脑【第29台电脑】电脑名称=联想,电脑价格5600.2
取走电脑【第29台电脑】电脑名称=联想,电脑价格5600.2
生产电脑【第30台电脑】电脑名称=联想,电脑价格5600.2
取走电脑【第30台电脑】电脑名称=联想,电脑价格5600.2
生产电脑【第31台电脑】电脑名称=联想,电脑价格5600.2
取走电脑【第31台电脑】电脑名称=联想,电脑价格5600.2
生产电脑【第32台电脑】电脑名称=联想,电脑价格5600.2
取走电脑【第32台电脑】电脑名称=联想,电脑价格5600.2
3、实现一个竞拍抢答程序:要求设置三个抢答者(三个线程),而后同时发出抢答指令,抢答成功者给出成功提示,未抢答成功者给出失败提示。
public class MyThread implements Callable<String> {
private boolean flag=false; //抢答处理
@Override
public String call() throws Exception {
synchronized (this) {//数据同步
if (this.flag==false) { //抢答成功
this.flag=true;
return Thread.currentThread().getName()+"抢答成功";
}else {
return Thread.currentThread().getName()+"抢答失败";
}
}
}
}
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Thread03 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
MyThread mt=new MyThread();
FutureTask<String> task1=new FutureTask<String>(mt);
FutureTask<String> task2=new FutureTask<String>(mt);
FutureTask<String> task3=new FutureTask<String>(mt);
new Thread(task1,"竞赛者A").start();
new Thread(task2,"竞赛者B").start();
new Thread(task3,"竞赛者C").start();
System.out.println(task1.get());
System.out.println(task2.get());
System.out.println(task3.get());
}
}
执行结果
竞赛者A抢答成功
竞赛者B抢答失败
竞赛者C抢答失败
填空题
1、 Java多线程可以依靠 ____ Runnable___ 和 ___ Callable_______ 两个接口实现,但是不管使用何种方式一定要通过 ____ Thread_____ 类 _start() __ 方法启动多线程。
2、 多个线程操作同一资源的时候需要注意 __ 同步___ ,依靠 _ synchronized _____ 关键字实现,实现手段是: _ 同步代码块 _____ 和 **同步方法** ______ ,过多的使用,则会出现 死锁 _ 问题。
3、 Java程序运行时,在每一个JVM进程之中一定会存在有 ___ main __ 线程。
4、 main线程的优先级是 中等优先级 _ 。
5、 线程在生命周期中要经历五种状态,分别是 __ 创建___ 状态、 __ 就绪____ 状态、 **运行** 状态、 _堵塞___ 状态、_销毁___ 状态。
6、 Object类提供的 wait() ___ notify() 、 notifyAll() 三个方法可以控制线程。
选择题
1、 线程的启动方法是 B_ 。
A、 run() B、 start() C、 begin() D、 accept()
2、 Thread类提供表示线程优先级的静态常量,代表普通优先级的静态常量是 D 。
A、 MAX_PRIORITY B、 MIN_PRIORITY
C、 NORMAL_PRIORITY D、 NORM_PRIORITY
3、 设置线程优先级的方法是 A__ 。
A、 setPriority() B、 getPriority() C、 getName() D、 setName()
4、 Thread类的 D 方法是不建议使用的?
A、 stop() B、 suspend() C、 resume() D、 全部都是
5、 下列 C__ 关键字通常用赖对对象加锁,从而似的对对象的访问是排他的。
A、 serialize B、 transient C、 synchronized D、 static
判断题
1、 Java中直接调用Thread类中的run()方法可以启动一个线程。 ( × )
2、 进程是在线程的基础之上的进一步划分。 ( √ )
3、 Java是多线程的编程语言。 ( √ )
简答题
1、 简述线程两种实现方式及区别?
答: 多线程的两种实现方式都需要一个线程的主类,而这个类可以实现Runnable接口或继承Thread类,不管使用何种方式都必须在子类之中覆写run()方法,此方法为线程的主方法;
Thread类是Runnable接口的子类,而且使用Runnable接口可以避免单继承局限,以及更加方便的实现数据共享的概念。
2、 简述死锁的产生。
答: 当多个线程访问某一共享资源时,为保证数据的正确性,需要使用同步进行控制,线程同步指的是某一线程要等待其他线程对象操作完成之后才可以进行操作,但是在程序之中过多的线程等待就会出现死锁。