Java9-day06【线程、同步、线程状态】课后习题

练习一:多线程开启

问题:

请描述Thread类中的start()方法与run()方法的区别。

答:

线程对象调用run()方法不开启线程,仅是对象调用方法。线程对象调用start()方法开启线程,并让jvm调用run()方法在开启的线程中执行。

练习二:创建多线程

问题:

请描述创建线程的两种方式。

答:

第一种方式是将类声明为 Thread 的子类。

  • 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把run()方法称为线程执行体。
  • 创建Thread子类的实例,即创建了线程对象。
  • 调用线程对象的start()方法来启动该线程。

第二种方式声明一个类实现Runnable 接口。

  • 定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
  • 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,Thread对象才是真正的线程对象。
  • 调用线程对象的start()方法来启动线程。

练习三:多线程练习

问题:

请编写程序,分别打印主线程的名称和子线程的名称。

要求使用两种方式实现:

第一种方式:继承Thread类。

第二种方法:实现Runnable接口。

答:

操作步骤描述

  • 第一种方式:继承Thread类

1.定义一个子线程的类,继承Thread类;

2.在子线程类中重写run方法,在run方法中打印子线程的名称;

3.定义一个测试类;

4.在main方法中打印主线程的名称;

5.在main方法中创建子线程对象;

6.调用子线程对象的start方法,开启子线程;

  • 第二种方式:实现Runnable接口

1.定义一个子任务类,实现Runnable接口;

2.在子任务类中重写run方法,在run方法中打印子线程的名称;

3.定义一个测试类;

4.在main方法中打印主线程的名称;

5.在main方法中创建一个子任务对象;

6.在main方法中创建一个Thread类的对象,并把子任务对象传递给Thread类的构造方法;

7.调用Thread类对象的start方法开启子线程;

操作步骤答案

  • 第一种方式:继承Thread类
/*
 * 1.定义一个子线程的类,继承Thread类;
 */
public class SubThread extends Thread {
 /*
  *2.在子线程类中重写run方法,在run方法中打印子线程的名称;
  */
 public void run() {
  // 打印子线程的名称
  System.out.println("subThread:" + Thread.currentThread().getName());
 }
} 
/*
 * 3.定义一个测试类
 */
public class ThreadDemo {
 public static void main(String[] args) {
  // 4.在main方法中打印主线程的名称;
  System.out.println("main:" + Thread.currentThread().getName());
  // 5.在main方法中创建子线程对象;
  SubThread st = new SubThread();
  // 6.调用子线程对象的start方法,开启子线程。
  st.start();
 }
}
  • 第二种方式:实现Runnable接口
/*
 * 1.定义一个子任务类,实现Runnable接口。
 */
public class SubRunnable implements Runnable {
 @Override
 public void run() {
  // 2.在子任务类中重写run方法,在run方法中打印子线程的名称。
  System.out.println("SubRunnable:"+ Thread.currentThread().getName());
 }
}
/*
 * 3.定义一个测试类。
 */
public class RunnableDemo {
 public static void main(String[] args) {
  // 4.在main方法中打印主线程的名称。
  System.out.println("RunnableDemo:"+ Thread.currentThread().getName());
  // 5.在main方法中创建一个子任务对象。
  SubRunnable r = new SubRunnable();
  // 6.在main方法中创建一个Thread类的对象,并把子任务对象传递给Thread类的                         构造方法。
  Thread t = new Thread(r);
  // 7.调用Thread类对象的start方法开启子线程。
  t.start();
 }
}

练习四:实现Runnable接口的优势

问题:

请描述实现Runnable接口比继承Thread类所具有的优势:

答:

1. 适合多个相同的程序代码的线程去共享同一个资源。

2. 可以避免java中的单继承的局限性。

3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和数据独立。

4. 线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类。

练习五:线程状态

问题:请描述在线程的生命周期中, 有几种状态呢 ?

答:

  • NEW(新建) 线程刚被创建,但是并未启动。
  • Runnable(可运行)

线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操作系统处理器。

  • Blocked(锁阻塞)

当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。

  • Waiting(无限等待)

一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。

  • Timed Waiting(计时等待)

同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、Object.wait。

  • Teminated(被终止)

因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。

练习六:多线程练习

问题:

编写程序,在主线程中,循环输出“主线程执行”;在一条新线程中,循环输出“子线程执行”

public class Son implements Runnable {

 public void run() {
  while (true) {
   System.out.println("子线程执行....");
  }
 }

} 

答:

//1.创建一个子线程类

public class Son implements Runnable {

 public void run() {
  while (true) {
   System.out.println("子线程执行....");
  }
 }

}

//2.创建一个测试类

public class Test06 {
 public static void main(String[] args) {
  //创建一个子线程对象
  Thread son = new Thread(new Son());
  son.start();//开启子线程
  while (true) {
   System.out.println("主线程执行");
  }
 }

练习七:多线程匿名内部类练习

问题:

编写程序,创建两个线程对象,一根线程循环输出“播放背景音乐”,另一根线程循环输出“显示画面”,要求线程实现Runnable接口,且使用匿名内部类实现

答://1.定义一个测试类

public class Test07 {

 public static void main(String[] args) {

  //1.新建第一条线程并开启
  new Thread(new Runnable() {
   @Override
   public void run() {
    while (true) {
     System.out.println("播放背景音乐");
    }
   }
  }).start();


  //2.新建第二条线程并开启
  new Thread(new Runnable() {
   @Override
   public void run() {
    while (true) {
     System.out.println("显示画面");
    }
   }
  }).start();
 }
}

练习八:多线程练习

问题:

编写一个Java程序,要求在同一个类中除main线程外,再开启一个线程,2个线程都循环执行20次。

答:

  //1.定义一个测试类

public class Test08 extends Thread {
 int a = 1;

 public static void main(String[] args) {
  Test08 thread = new Test08();
  thread.start();
  for (int i = 1; i <= 20; i++) {
   System.out.println(Thread.currentThread().getName() + "执行第:" + i + "次");
  }
 }

 @Override
 public void run() {
  for (; a <= 20; a++) {
   System.out.println(Thread.currentThread().getName() + "执行第:" + a + "次");
  }
 }
} 

练习九:多线程练习

问题:

请按要求编写多线程应用程序,模拟多个人通过一个山洞:

1.这个山洞每次只能通过一个人,每个人通过山洞的时间为5秒;

2.随机生成10个人,同时准备过此山洞,并且定义一个变量用于记录通过隧道的人数。显示每次通过山洞人的姓名,和通过顺序;

答:

操作步骤描述

  • 定义一个隧道类,实现Runnable接口:
    • 定义一个变量,用来记录通过隧道的人数;
    • 重写Runnable的run方法;
    • 定义一个同步方法,模拟每个人通过隧道需要5秒钟:
      • 子线程睡眠5秒钟,模拟每个人通过隧道需要5秒钟;
      • 改变通过的人次;
      • 打印线程名称及其通过隧道的顺序,模拟人通过隧道及其顺序;
    • 调用通过隧道的方法;
  • 2.定义一个测试类:
    • 在main方法中创建一个隧道类对象;
    • 在main方法中,循环创建10个子线程对象,通过构造方法把隧道对象和线程名(作为人的姓名)传递进去,并开启子线程;

操作步骤答案

/*
 * 1.定义一个隧道类,实现Runnable接口
 */

public class Tunnel implements Runnable {

 // 1.1 定义一个变量,用来记录通过隧道的人数
 private int crossNum = 0;

 /*
  * 1.2 重写Runnable的run方法
  */
 @Override
 public void run() {
  // 1.4 调用通过隧道的方法
  cross();
 }

 /*
  * 1.3 定义一个同步方法,模拟每个人通过隧道需要5秒钟
  */
 public synchronized void cross() {
  // 1.3.1 子线程睡眠5秒钟,模拟每个人通过隧道需要5秒钟
  try {
   Thread.sleep(5000);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  // 1.3.2 改变通过的人次
  crossNum++;
  // 1.3.3 打印线程名称及其通过隧道的顺序,模拟人通过隧道及其顺序
  System.out.println(Thread.currentThread().getName() + "已经通过隧道,TA是第" + crossNum + "通过的!");
 }
}
/*
 * 2.定义一个测试类
 */

public class TunnelDemo {

 public static void main(String[] args) {
  // 2.1 在main方法中创建一个隧道类对象
  Tunnel tul = new Tunnel();

  // 2.2 在main方法中,循环创建10个子线程对象,通过构造方法把隧道对象和// 线程名(作为人的姓名)传递进去,并开启子线程
  for (int i = 1; i <= 10; i++) {
   Thread t = new Thread(tul, "p" + i);
   t.start();
  }
 }
}

原创文章,作者:小助手,如若转载,请注明出处:https://www.javahelp.com.cn/742.html

(0)
上一篇 2022年8月31日 上午12:03
下一篇 2022年8月31日 下午1:23

相关推荐

发表回复

登录后才能评论