JAVA面试题 start()和run()详解

问题

面试官:请问启动线程是start()还是run()方法,能谈谈吗?

应聘者:start()方法

当用start()开始一个线程后,线程就进入就绪状态,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行。但是这并不意味着线程就会立即运行。只有当cpu分配时间片时,这个线程获得时间片时,才开始执行run()方法。start()是方法,它调用run()方法.而run()方法是你必须重写的. run()方法中包含的是线程的主体(真正的逻辑)。

继承Thread类的启动方式

public class ThreadTest {
  public static void main(String[] args) {
    MyThread t =new MyThread();
    t.start();
  }
}

class MyThread extends Thread{
  @Override
  public void run() {
    System.out.println("Hello World!");
  }
}

实现Runnable接口的启动方式

public class ThreadTest {
   public static void main(String[] args) {
    Thread t =new Thread(new MyRunnable());
    t.start();
  }
}

class MyRunnable implements Runnable{
  @Override
  public void run() {
    System.out.println("Hello World!");
  }
}

实际上这两种启动线程的方式原理是一样的。首先都是调用本地方法启动一个线程,其次是在这个线程里执行目标对象的run()方法。那么这个目标对象是什么呢?为了弄明白这个问题,我们来看看Thread类的run()方法的实现:

public void run() {
  if (target != null) {
    target.run();
  }
}

当我们采用实现Runnable接口的方式来实现线程的情况下,在调用new Thread(Runnable target)构造器时,将实现Runnable接口的类的实例设置成了线程要执行的主体所属的目标对象target,当线程启动时,这个实例的 run()方法就被执行了。

当我们采用继承Thread的方式实现线程时,线程的这个run()方法被重写了,所以当线程启动时,执行的是这个对象自身的 run()方法。

总结起来:如果我们采用的是继承Thread类的方式,那么这个target就是线程对象自身,如果我们采用的是实现Runnable接口的方式,那么这个target就是实现了Runnable接口的类的实例。

我们再来看一道混迹于各大面试公司笔试的题目:

public class EqualsTest {
   public static void main(String args[]) {
     Thread t = new Thread() {
       public void run() {
         pong();
       }
     };
     t.run();
     System.out.print("ping");

  }

  static void pong() {
    System.out.print("pong");
  }
}

这里的标准答案是:pongping

这里直接调用线程的run方法,就相当于调用普通方法一样,由上往下执行,所以最后的结果是pongping。但是如果上面改成t.start()之后,这个结果就不固定了,因为这里有两个线程(其实还有一个守护线程,这里就先忽略),main线程和 t 线程,这两个线程获得cpu的时间就会不固定了,谁先获得CPU执行权,谁就先打印结果,所以最后的结果可能pongping也可能是pingpong。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • JAVA面试题 从源码角度分析StringBuffer和StringBuilder的区别

    面试官:请问StringBuffer和StringBuilder有什么区别? 这是一个老生常谈的话题,笔者前几年每次面试都会被问到,作为基础面试题,被问到的概率百分之八九十.下面我们从面试需要答到的几个知识点来总结一下两者的区别有哪些? 继承关系? 如何实现的扩容? 线程安全性? 继承关系 从源码上看看类StringBuffer和StringBuilder的继承结构: 从结构图上可以直到,StringBuffer和StringBuiler都继承自AbstractStringBuilder类 如何

  • JAVA面试题 简谈你对synchronized关键字的理解

    面试官:sychronized关键字有哪些特性? 应聘者: 可以用来修饰方法; 可以用来修饰代码块; 可以用来修饰静态方法; 可以保证线程安全; 支持锁的重入; sychronized使用不当导致死锁; 了解sychronized之前,我们先来看一下几个常见的概念:内置锁.互斥锁.对象锁和类锁. 内置锁 在Java中每一个对象都可以作为同步的锁,那么这些锁就被称为内置锁.线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁.获得内置锁的唯一途径就是进入这个锁的保护的同

  • Java面试题 从源码角度分析HashSet实现原理

    面试官:请问HashSet有哪些特点? 应聘者:HashSet实现自set接口,set集合中元素无序且不能重复: 面试官:那么HashSet 如何保证元素不重复? 应聘者:因为HashSet底层是基于HashMap实现的,当你new一个HashSet时候,实际上是new了一个map,执行add方法时,实际上调用map的put方法,value始终是PRESENT,所以根据HashMap的一个特性: 将一个key-value对放入HashMap中时,首先根据key的hashCode()返回值决定该E

  • JAVA面试题String产生了几个对象

    面试官Q1:请问String s = new String("xyz");产生了几个对象? 对于这个Java面试题,老套路先上代码: public class StringTest { public static void main(String[] args){ String s1="Hello"; String s2="Hello"; String s3=new String("Hello"); System.out.pr

  • Java工程师面试题一面二面整理

    秀强信息公司关于JAVA的面试内容 这个公司做学前教育,老板喜欢谈理想和谈情怀来压工资.属于18年年底成立的小公司,Java开发三个人吧. 一面(电话): 1.服务没挂,但是不可用的,Nginx感知不到,怎么办? 2.下单过程库存是怎么处理的?下单卡住多久释放锁定的库存? 3.多线程同步?synchronized,wait,notify.notifyALL 4.wait和sleep以及yield 5.HashMap和ConcurrentHashMap 6.ThreadLocal用过吗? 7.Re

  • JAVA面试题 start()和run()详解

    问题 面试官:请问启动线程是start()还是run()方法,能谈谈吗? 应聘者:start()方法 当用start()开始一个线程后,线程就进入就绪状态,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行.但是这并不意味着线程就会立即运行.只有当cpu分配时间片时,这个线程获得时间片时,才开始执行run()方法.start()是方法,它调用run()方法.而run()方法是你必须重写的. run()方法中包含的是线程的主体(真正的逻辑). 继承Thread类的启动方式 p

  • java 多线程与并发之volatile详解分析

    目录 CPU.内存.缓存的关系 CPU缓存 什么是CPU缓存 为什么要有多级CPU Cache Java内存模型(Java Memory Model,JMM) JMM导致的并发安全问题 可见性 原子性 有序性 volatile volatile特性 volatile 的实现原理 总结 CPU.内存.缓存的关系 要理解JMM,要先从计算机底层开始,下面是一份大佬的研究报告 计算机在做一些我们平时的基本操作时,需要的响应时间是不一样的!如果我们计算一次a+b所需要的的时间: CPU读取内存获得a,1

  • Java并发编程Semaphore计数信号量详解

    Semaphore 是一个计数信号量,它的本质是一个共享锁.信号量维护了一个信号量许可集.线程可以通过调用acquire()来获取信号量的许可:当信号量中有可用的许可时,线程能获取该许可:否则线程必须等待,直到有可用的许可为止. 线程可以通过release()来释放它所持有的信号量许可(用完信号量之后必须释放,不然其他线程可能会无法获取信号量). 简单示例: package me.socketthread; import java.util.concurrent.ExecutorService;

  • Java并发编程总结——慎用CAS详解

    一.CAS和synchronized适用场景 1.对于资源竞争较少的情况,使用synchronized同步锁进行线程阻塞和唤醒切换以及用户态内核态间的切换操作额外浪费消耗cpu资源:而CAS基于硬件实现,不需要进入内核,不需要切换线程,操作自旋几率较少,因此可以获得更高的性能. 2.对于资源竞争严重的情况,CAS自旋的概率会比较大,从而浪费更多的CPU资源,效率低于synchronized.以java.util.concurrent.atomic包中AtomicInteger类为例,其getAn

  • Java AtomicInteger类的使用方法详解

    首先看两段代码,一段是Integer的,一段是AtomicInteger的,为以下: public class Sample1 { private static Integer count = 0; synchronized public static void increment() { count++; } } 以下是AtomicInteger的: public class Sample2 { private static AtomicInteger count = new AtomicIn

  • Java CountDownLatch完成异步回调实例详解

    Java CountDownLatch完成异步回调实例详解 实例代码: public class AsyncDemo { private static void doSomeTask() { System.out.println("Hello World"); } private static void onCompletion() { System.out.println("All tasks finished"); } public static void ma

  • Java中CountDownLatch进行多线程同步详解及实例代码

    Java中CountDownLatch进行多线程同步详解 CountDownLatch介绍 在前面的Java学习笔记中,总结了Java中进行多线程同步的几个方法: 1.synchronized关键字进行同步. 2.Lock锁接口及其实现类ReentrantLock.ReadWriteLock锁实现同步. 3.信号量Semaphore实现同步. 其中,synchronized关键字和Lock锁解决的是多个线程对同一资源的并发访问问题.信号量Semaphore解决的是多副本资源的共享访问问题. 今天

  • java 中死锁问题的实例详解

    java 中死锁问题的实例详解 先看代码在做解释 public class DeadLock implements Runnable{ String a; String b; boolean flag; public DeadLock(String a,String b,boolean flag){ this.a=a; this.b=b; this.flag=flag; } public void run(){ if(flag){ // while(true){ synchronized(a){

  • Java 中synchronize函数的实例详解

    Java 中synchronize函数的实例详解 java中的一个类的成员函数若用synchronized来修饰,则对应同一个对象,多个线程像调用这个对象的这个同步函数时必须等到上一个线程调用完才能由下一个线程调用. 那么如果一个类同时有两个成员函数是由synchronized修饰如代码所示,对与同一个对象,是否可以在两个线程运行时,一个调用funcA,同时另一个调用funcB? Mysyn是这样一个类,如果我有两个线程,一个在run方法中先运行funcA再运行funcB,另一个线程在run方法

  • Java连接操作Oracle数据库代码详解

    废话不多说了,直接给大家贴关键代码了,具体代码如下所示: package com.sp.test; import java.sql.*; import java.util.*; public class Text_lianxi extends Thread { public void run() { try { yunxing(); Thread.sleep(10000); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.pr

随机推荐