1. 使用多线程有什么好处?
多线程有多种好处,如下所示:
- 即使程序的一部分被阻塞,也允许程序继续运行。
- 与使用多个进程的传统并行程序相比,提高了性能。
- 允许编写利用最大 CPU 时间的有效程序
- 提高复杂应用程序或程序的响应能力。
- 增加 CPU 资源的使用并降低维护成本。
- 节省时间和并行任务。
- 如果在单个线程中发生异常,它不会影响其他线程,因为线程是独立的。
- 与同时执行多个进程相比,资源密集型更少。
2. Java中的线程是什么?
线程基本上是可以由调度程序独立管理的轻量级和最小的处理单元。线程被称为进程的一部分,它只是让程序与进程的其他部分或线程同时有效地执行。使用线程,可以以最简单的方式执行复杂的任务。它被认为是利用机器中可用的多个 CPU 的最简单方法。它们共享公共地址空间并且彼此独立。
3. Java实现线程的两种方式是什么?
在java中实现线程基本上有两种方法,如下所示:
- 扩展线程类
例子:
class MultithreadingDemo extends Thread { public void run() { System.out.println("My thread is in running state."); } public static void main(String args[]) { MultithreadingDemoobj=new MultithreadingDemo(); obj.start(); } }
输出:
My thread is in running state.
- 在 Java 中实现Runnable接口
示例
class MultithreadingDemo implements Runnable { public void run() { System.out.println("My thread is in running state."); } public static void main(String args[]) { MultithreadingDemo obj=new MultithreadingDemo(); Threadtobj =new Thread(obj); tobj.start(); } }
输出:
My thread is in running state.
4. 线程和进程有什么区别?
线程:它只是指特定进程的最小单元。它具有同时执行程序的不同部分(称为线程)的能力。
进程:它只是指正在执行的程序,即活动程序。可以使用 PCB(过程控制块)处理过程。
线 | 过程 |
它是进程子单元的子集。 | 它是一个包含多个线程的正在执行的程序。 |
在这种情况下,线程间通信更快、更便宜、更容易、更高效,因为线程共享它们所属进程的相同内存地址。 | 在这种情况下,进程间通信更慢、更昂贵、更复杂,因为每个进程都有不同的内存空间或地址。 |
这些更容易创建、轻量级并且开销更少。 | 这些很难创建,重量级,并且有更多的开销。 |
它需要更少的时间来创建、终止和上下文切换。 | 它需要更多的时间来创建、终止和上下文切换。 |
具有多个线程的进程使用较少的资源。 | 没有线程的进程使用更多资源。 |
线程是进程的一部分,因此它们相互依赖,但每个线程独立执行。 | 进程相互独立。 |
需要在线程中进行同步以避免意外情况或问题。 | 每个进程都不需要同步。 |
他们彼此共享数据和信息。 | 他们不相互共享数据。 |
5. 类的锁和对象锁有什么区别?
类锁:在java中,每个类都有一个唯一的锁,通常称为类级锁。这些锁是使用关键字“静态同步”实现的,可用于使静态数据线程安全。它通常在想要防止多个线程进入同步块时使用。
例子:
public class ClassLevelLockExample { public void classLevelLockMethod() { synchronized (ClassLevelLockExample.class) { //DO your stuff here } } }
对象锁:在java中,每个对象都有一个唯一的锁,通常称为对象级锁。这些锁是使用关键字“synchronized”实现的,可用于保护非静态数据。它通常在想要同步非静态方法或块时使用,以便只有线程能够在给定的类实例上执行代码块。
示例 :
public class ObjectLevelLockExample { public void objectLevelLockMethod() { synchronized (this) { //DO your stuff here } } }
护进程基本上是 Java 中使用“线程类”的两种类型的线程。
用户线程(非守护线程):在 Java 中,用户线程具有特定的生命周期,其生命周期独立于任何其他线程。JVM(Java 虚拟机)在终止之前等待任何用户线程完成其任务。当用户线程完成时,JVM 会终止整个程序以及相关的守护线程。
守护线程:在Java中,守护线程基本上被称为服务提供者,为用户线程提供服务和支持。守护线程的线程类中基本上有两种可用的方法:setDaemon() 和 isDaemon()。
用户线程与守护线程
用户线程 | 守护线程 |
JVM 在终止前等待用户线程完成其任务。 | JVM 在终止前不会等待守护线程完成其任务。 |
这些线程通常由用户创建,用于并发执行任务。 | 这些线程通常由 JVM 创建。 |
它们用于应用程序的关键任务或核心工作。 | 它们不用于任何关键任务,而是用于执行一些辅助任务。 |
这些线程被称为高优先级任务,因此需要在前台运行。 | 这些线程被称为低优先级线程,因此特别需要支持后台任务,如垃圾收集、释放未使用对象的内存等。 |
7.我们如何创建守护线程?
我们可以使用线程类setDaemon(true)在 java 中创建守护线程。它用于将当前线程标记为守护线程或用户线程。isDaemon()方法一般用于检查当前线程是否为守护进程。如果线程是守护进程,它将返回 true,否则返回 false。
示例
**说明 setDaemon() 和 isDaemon() 方法使用的程序。**
public class DaemonThread extends Thread { public DaemonThread(String name){ super(name); } public void run() { // Checking whether the thread is Daemon or not if(Thread.currentThread().isDaemon()) { System.out.println(getName() + " is Daemon thread"); } else { System.out.println(getName() + " is User thread"); } } public static void main(String[] args) { DaemonThread t1 = new DaemonThread("t1"); DaemonThread t2 = new DaemonThread("t2"); DaemonThread t3 = new DaemonThread("t3"); // Setting user thread t1 to Daemon t1.setDaemon(true); // starting first 2 threads t1.start(); t2.start(); // Setting user thread t3 to Daemon t3.setDaemon(true); t3.start(); } }
输出:
t1 is Daemon thread t3 is Daemon thread t2 is User threa
但是只能在start() 方法之前调用 setDaemon()方法,否则肯定会抛出 IllegalThreadStateException,如下所示:
public class DaemonThread extends Thread { public void run() { System.out.println("Thread name: " + Thread.currentThread().getName()); System.out.println("Check if its DaemonThread: " + Thread.currentThread().isDaemon()); } public static void main(String[] args) { DaemonThread t1 = new DaemonThread(); DaemonThread t2 = new DaemonThread(); t1.start(); // Exception as the thread is already started t1.setDaemon(true); t2.start(); } }
8. wait() 和 sleep() 方法是什么?
wait():顾名思义,它是一种非静态方法,它会导致当前线程等待并进入睡眠状态,直到其他一些线程为对象的监视器(锁)调用 notify() 或 notifyAll() 方法。它只是释放锁,主要用于线程间通信。它在对象类中定义,并且只能从同步上下文中调用。
synchronized(monitor) { monitor.wait(); Here Lock Is Released by Current Thread }
sleep():顾名思义,它是一种静态方法,可以暂停或停止当前线程的执行一段时间。它在等待时不会释放锁,主要用于在执行时引入暂停。它在线程类中定义,无需从同步上下文中调用。
synchronized(monitor) { Thread.sleep(1000); Here Lock Is Held by The Current Thread //after 1000 milliseconds, the current thread will wake up, or after we call that is interrupt() method }
9. notify() 和 notifyAll() 有什么区别?
notify():它发送一个通知并且只唤醒一个线程而不是多个线程在对象的监视器上等待。
notifyAll():它发送通知并唤醒所有线程并允许它们竞争对象的监视器而不是单个线程。
10. 为什么 Object 类中存在 wait()、notify() 和 notifyAll() 方法?
我们知道每个对象都有一个监视器,它允许线程持有对象上的锁。但是线程类不包含任何监视器。线程通常通过调用对象的wait()方法等待对象的监视器(锁),并使用notify()或notifyAll()方法通知正在等待同一锁的其他线程。因此,这三个方法仅在对象上调用,并允许所有线程与在该对象上创建的每个线程进行通信。
11.什么是Runnable和Callable接口?写出它们之间的区别
这两个接口一般都用于封装需要由另一个线程执行的任务。但是它们之间有一些区别,如下所示:
运行接口:这个接口基本上从一开始就在 Java 中可用。它仅用于在并发线程上执行代码。
可调用接口:这个接口基本上是作为并发包的一部分引入的新接口。它解决了可运行接口的限制以及一些重大变化,如泛型、枚举、静态导入、变量参数方法等。它使用泛型来定义对象的返回类型。
public interface Runnable { public abstract void run(); } public interface Callable<V> { V call() throws Exception; }
可运行接口与可调用接口
可运行接口 | 可调用接口 |
它不返回任何结果,因此不能抛出检查异常。 | 它返回一个结果,因此可以抛出异常。 |
它不能传递给 invokeAll 方法。 | 它可以传递给 invokeAll 方法。 |
它是在 JDK 1.0 中引入的。 | 它是在 JDK 5.0 中引入的,因此在 Java 5 之前不能使用它。 |
它只是属于 Java.lang。 | 它只是属于 java.util.concurrent。 |
它使用 run() 方法来定义任务。 | 它使用 call() 方法来定义任务。 |
要使用此接口,需要重写 run() 方法。 | 要使用此接口,需要重写 call() 方法 |