Java中的线程

22

我在今天的一次Java技术面试中被问到了关于线程概念的问题,具体问题如下:

  1. 什么是线程?
  2. 我们为什么要使用线程?
  3. 一个关于线程的实时例子。
  4. 能否在Spring框架服务类中创建线程。
  5. Flex可以调用线程吗?

除了线程的定义,我对其他问题都没有回答,而且这个定义我也只是从互联网上学习到的。

请问有人能够清晰地解释这些问题吗?

更新:

线程和普通Java类的区别是什么?为什么我们需要使用多线程?我可以在线程中执行业务逻辑吗?我可以在线程中调用不同类的方法吗?


4
我不了解4或5的内容,但是如果在面试中没有基本的1-3题答案的话,对我来说似乎有点奇怪(也就是说,这些问题与Java无关)。 - Rhangaun
请添加面试问题标签。 - Hugh Brackett
8个回答

23

创建线程需要创建一个新类,该类继承Thread类并实例化该类。子类必须重写run方法并调用start方法来开始执行线程。

run内部,您将定义构成新线程的代码。理解这一点很重要,因为run可以调用其他方法,使用其他类和声明变量,就像主线程一样。唯一的区别是run在程序中建立了另一个并发执行的线程的入口点。当run返回时,此线程将结束。

下面是一个示例:

public class MyThread extends Thread {
    private final String name;

    public MyThread(String name) {
        this.name = name;
    }

    public void run() {
        try {
            for (; ; ) {
                System.out.println(name);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            System.out.println("sleep interrupted");
        }
    }

    public static void main(String[] args) {
        Thread t1 = new MyThread("First Thread");
        Thread t2 = new MyThread("Second Thread");
        t1.start();
        t2.start();
    }
}

您将在屏幕上看到以下内容:

First Thread
Second Thread
First Thread
Second Thread
First Thread

这篇教程还解释了Runnable接口。使用Spring,你可以使用线程池


猜测这与Spring调度无关? - ukanth
1
最好的做法是实现Runnable接口,然后将一个Runnable实例传递给Thread构造函数,而不是继承Thread类。 - Adamski
1
@TiNS:我并没有指向Spring调度,我插入了关于Spring中调度和线程池的链接。 - Sajad Bahmani
虽然这样做是正确的,但我建议不要创建和启动线程。相反,使用java.concurrent包创建和配置执行器,安排任务运行,并使用提供的同步原语。 - Jilles van Gurp

12

多线程是Java的一项功能,它允许程序的两个或多个部分并发执行,以最大限度地利用CPU。这种程序的每个部分都称为一个线程。

线程是进程内的轻量级进程。

可以使用两种机制创建线程:

  1. 扩展Thread类
  2. 实现Runnable接口

通过扩展Thread类创建线程

我们创建一个扩展java.lang.Thread类的类。该类重写Thread类中可用的run()方法。线程在run()方法内开始其生命周期。我们创建一个新类的对象,并调用start()方法来启动线程的执行。start()在Thread对象上调用run()方法。

class MultithreadingDemo extends Thread{
public void run()    {
    try {   // Displaying the thread that is running
        System.out.println ("Thread " + Thread.currentThread().getId() 
                                + " is running"); 
        }
        catch (Exception e){   // Throwing an exception
            System.out.println ("Exception is caught");
        }
    }
} 
public class Multithread{
    public static void main(String[] args)    {
        int n = 8; // Number of threads
        for (int i=0; i<8; i++)        {
            MultithreadingDemo object = new MultithreadingDemo();
            object.start();
        }
    }
}

通过实现Runnable接口创建线程

我们创建一个新的类,并实现java.lang.Runnable接口,重写run()方法。然后,我们实例化一个Thread对象,并在该对象上调用start()方法。

class MultithreadingDemo implements Runnable{
public void run()    {
    try   {     // Displaying the thread that is running
        System.out.println ("Thread " +  Thread.currentThread().getId() +
                            " is running");

    }
    catch (Exception e)   {     // Throwing an exception
        System.out.println ("Exception is caught");
    }
    }
} 
class Multithread{
    public static void main(String[] args)    {
        int n = 8; // Number of threads
        for (int i=0; i<8; i++)        {
            Thread object = new Thread(new MultithreadingDemo());
            object.start();
        }
    }
}

Thread类与Runnable接口的区别

  1. 如果我们扩展Thread类,我们的类就不能再扩展任何其他类,因为Java不支持多重继承。但是,如果我们实现Runnable接口,我们的类仍然可以扩展其他基类。

  2. 通过扩展Thread类,我们可以实现线程的基本功能,因为它提供了一些内置方法,如yield()、interrupt()等,在Runnable接口中不可用。


3

我可以回答前三个问题,因为我对Spring或Flex的线程功能不太熟悉。

  1. 线程是一个对象,它具有自己的寄存器和堆栈,可以与进程中的其他线程并行运行(进程是线程的集合)。

  2. 编写多线程代码是为了使程序对用户交互更加响应。想象一下,如果你必须等待浏览器完成下载文件才能继续浏览,那会有多烦人。

  3. 我在第二点中举了一个例子。其他例子包括任何带有GUI的程序(GUI必须始终对用户输入做出响应,同时执行后台任务),或者服务器类型软件,例如Web服务器,可能需要响应1000个请求每分钟。最好为每个响应使用单独的线程。


2

需要澄清的一个关键概念是,线程是操作系统调度对象,只是恰好有一个 Java 类来表示它(就像 UI 子系统中的 Window 一样)。线程本身并不是一种类。


2

Flex无法直接与Java线程通信,必须通过某种消息传递方式进行通信,无论您使用JMS还是其他方式,Flex通过BlazeDS、GraniteDS或LCDS可以与JMS通信。还要记住的一件事是,目前Flash/Flex本身是单线程的,但高度异步...有些人会说太过于异步...因此,任何使用Java线程来加速处理可能不像您希望的那样有效。


1

请查看oracle tutorial

  1. 什么是线程?

线程有时被称为轻量级进程。线程存在于进程内 - 每个进程至少有一个线程。线程共享进程的资源,包括内存和打开的文件。这使得通信高效,但可能存在问题。

  1. Why do we go for threading?

    1. Multithreaded execution is an essential feature of the Java platform. Threads are independent of each other.

    2. You can parallelize your computation by breaking into multiple sub computations.

    3. You can use CPU cores of your server effectively.

    e.g.

    ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime()
                .availableProcessors());
    

    if you follow shared-nothing approach ( which is not possible always) between your threads, multi-threading application provides high throughput.

  2. A real time example over the threads.

    Think of WhatsApp kind of a chat application.

    The server should send and receive chat messages among thousands of users. A single threaded application is disaster to handle this use case.

线程和普通的Java类有什么区别?为什么我们需要线程... 我能在线程中执行业务逻辑吗?我能在线程中调用不同类的方法吗。

一个线程类可以实现Runnable或扩展Thread。请参阅Oracle教程page

您可以在线程中执行业务逻辑。

您可以在线程中调用不同类的方法。


1
就Spring而言,您绝对可以创建自己的线程。但最好使用Spring Framework手册第25章中描述的线程池支持。
然而,在Spring-based web service(或任何Web服务)中生成线程的请求会引入资源管理问题,可能需要避免...

0

简单来说,Java中的线程是指与普通类同时运行的程序/代码。线程与普通类的区别在于,线程可以并行地工作。

更简单地说,假设我当前在主函数中,并需要一个函数来计算某些内容。如果该函数不在线程中,则该函数将首先被评估,然后我将返回到主函数。另一方面,如果它是一个线程,则该函数将计算,而主函数也将计算其下一条指令。

现在来看看如何创建线程:

  1. 扩展线程类:扩展线程类并编写 start() 函数。使用当前类的对象调用此函数,并编写一个名为 void run() 的函数,在其中编写需要同时执行的代码。
  2. 每个扩展线程类的对象都是自定义线程。默认情况下,每个线程都处于非活动状态,要激活或调用该线程,只需编写 start() 即可,这将自动调用包含您代码的 run 函数。
class MyThreads extends Thread
{
 int ch ;

 MyThreads(int p)
 {
  ch = p;
  start();//statement to activate thread and call run
 }  

 public void run()
 {
  if(ch == 1)
    functionx()
  else if(ch == 2)
    functiony();

 }

 void fx1()
 {
  //parallel running code here
 }

 void fx2()
 {
    //parallel running code here
 }

 public static void main(String args[])
 {

  MyThreads obj1 = new MyThreads(1);
  My3Threads obj2 = new MyThreads(2);

  //mains next instruction code here

 }
}
  1. 你也可以实现一个接口,即Runnable,但由于这是一个与当前类兼容的接口,因此调用start将调用接口中编写的run()函数,但要调用我们自己的run()函数,请使用线程对象调用start,如下所示:Thread t=new thread(this); t.start();

现在来说为什么我们要使用线程,这就像问为什么我们要使用多核处理器,你知道我的意思,多线程用于并发执行任务。

一个实时的例子是服务器,任何服务器,考虑 Gmail 的服务器。如果 Gmail 服务器没有使用多线程编写,则我无法在您退出登录之前登录,这意味着在全世界只有一个人可以同时登录,你看到这是多么不切实际。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接