JAVA多线程

这篇博客探讨了JAVA多线程的相关知识,包括Thread类的start()和run()方法的区别,线程的六种生命周期状态,以及两种创建多线程的方式。作者通过实例展示了start()方法会启动新线程执行run(),而直接调用run()则不会。此外,还提出了一个模拟多人通过山洞的多线程问题,强调了线程同步的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天做点JAVA多线程的练习题来巩固一下多线程的相关知识,话不多说,直接上题。

Thread类中的start()方法与run()方法的区别

答:线程对象调用run()方法不开启线程,仅仅是对run()方法的调用。而start()方法会开启线程,并且让jvm调用run()方法在线程中执行。
在做这道题的时候,我发现了一个比较有趣的事情,下面两段代码的运行结果居然不是一样的,惊到我了。

public class Demo11 extends Thread{
   public static void main(String[] args){
   new Demo11().start();
   System.out.println("--------------");
   new Demo11().run();
   }
    @Override
    public void run() {
        System.out.println("abc");
    }
}
--------------
abc
abc
public class Demo11 extends Thread{
   public static void main(String[] args){
   new Demo11().run();
   System.out.println("--------------");
   new Demo11().start();
   }
    @Override
    public void run() {
        System.out.println("abc");
    }
}
abc
--------------
abc

第一段代码结果居然是先输出分隔的“----------”,想一想可能是start()方法会创建一个线程,而创建这个线程是需要时间的,所以导致了先输出了下一行代码。第二段代码先调用run()方法,这个几乎不消耗时间,所以会先执行。
那么这个想法是否是对的呢?
将上述run方法中的代码加上时间获取就可以知道线程运行的时间了。由于光输出一行耗的时间太少了,改写了下内容。

    public void run() {
        long start = System.currentTimeMillis();
        int sum = 0;
        for(int i = 0; i < 100;i++){
             sum += i;
             System.out.println(sum);
        }
        long end = System.currentTimeMillis();
        System.out.println("线程执行的时间:"+(end-start));
    }

由于代码结果比较长,就不截图了,直接说结论。
每次线程的运行时间都可能会有变化,总体来说,run方法和start方法在这个程序中耗时无明显差别。
但是run方法在前面的时候,会执行完run方法再输出分割线,是严格按照自上而下的顺序来执行的。
而start方法在第一行的时候,直接就输出了分隔线。
另外,我知道我这个设计思路有一个问题,得到的时间只是运行所花的时间,而创建线程是不是需要时间,需要多少时间是不知道的。这个问题就到这儿吧,超出我的认知范围了,记住结论就好。start方法会开启线程,run方法只是调用。好,下一题。

两种方式创建多线程

这道题目比较基础,也没有太多要思考的点,直接放上代码。
第一个实现Runnable方法

public  class Demo10 implements Runnable {
    @Override
    public void run() {
        for(int i = 0;i<10;i++){
            Thread.currentThread().setName("th02");
            System.out.println(Thread.currentThread().getName()+"第"+i+"次输出");
        }
    }
}

继承Thread类方法

public class Demo09 extends Thread{

    public static void main(String[] args){
         Thread th01 = new Demo09();
         th01.start();
         Runnable runnable = new Demo10();
         Thread th02 = new Thread(runnable);
         th02.start();

    }
    @Override
    public void run() {
        for(int i = 0; i < 10;i++){
            currentThread().setName("th01");
            System.out.println(currentThread().getName()+"第"+i+"次输出");
        }
    }
}

在线程的生命周期中,有几种状态?

NEW(新建)

线程刚刚被创建,但是未使用

Runnable(可运行)

线程可以在java中运行的状态 ,但是线程有没有运行并不知道

Blocked(锁阻塞)

当线程获取的对象是有锁的状态,且该对象被其他线程线程持有,则该线程进入Blocked状态;当线程有持有锁的时候变成Runnable状态

Waiting(无限等待)

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

Timed Waiting(计时等待)

不需要无限等待另一个线程调用唤醒,到了设定的时间会自动唤醒

Teminated(被终止)

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

匿名内部类创建多线程

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

 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();
 }

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

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

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 + "通过的!");
 }
}
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();
  }
 }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值