众所周知,多线程进程有多个控制序列,每个序列由一个线程控制,能够同时执行独立的任务。
在Java,多线程概念是通过使用以下两种模型来实现的。
1. 绿线模型
2. 原生线程模型
绿线模型
- 在这个模型中,线程完全由 JVM 管理,没有任何底层操作系统支持。
- 这些线程在应用程序级别实现并在用户空间进行管理。
- 它们也称为协作(用户级)线程。
- 一次只能加工一根绿线。因此,该模型被认为是多对一模型。因此,绿色线程可以在多核处理器上运行,但不能利用多核。
- 绿色线程更容易同步和资源共享,因此执行时间也更少。
- Sun Solaris OS 提供对绿色线程模型的支持。
本地线程模型
- 此模型中的线程由 JVM在底层操作系统支持的帮助下进行管理。
- 这些线程在操作系统级别实现(通过使用操作系统多线程 API)并在内核空间中管理。
- 它们也称为非绿色(内核级)线程。
- 多个本地线程可以共存。因此它也被称为多对多模型。该模型的这种特性使其能够充分利用多核处理器并在单独的单个内核上并发执行线程。
- 由于该模型允许多个线程同时执行,线程同步和资源共享变得复杂。这增加了线程的执行时间。
- 所有基于 Windows 的操作系统都提供对 Native Thread 模型的支持。
由于其局限性, Green Thread 模型已被弃用且不再使用。 Native Thread 模型已经取代了 Green Thread 模型,并且在今天被广泛使用。
除此之外, Java的 Thread 类还有一些不推荐使用的方法。
- 公共无效停止()
此方法已被弃用,因为使用它本质上是不安全的。例如,假设一个线程打开了一个文件并正在写入该文件。突然间,如果我们在这个线程上调用 stop() 方法,那么该线程将突然终止并且文件将保持打开状态。
这可能被认为是不安全的。因此,我们使用线程间通信和中断系统来通知线程停止执行一段时间,而不是强制线程停止执行。 - 公共无效暂停()
Thread.suspend() 方法已被弃用,因为它容易死锁。考虑一个示例,其中主线程持有对象上的锁并且该线程被挂起。在该线程恢复之前,没有其他线程可以获得该对象级锁定。如果辅助线程在主线程恢复之前尝试获取该对象的锁,则存在死锁情况。 - 公共无效简历()
由于 suspend() 方法被弃用,resume() 方法也被弃用。
下面的例子说明了使用 suspend() 方法是如何导致死锁的。
// Printer class
class Printer {
// synchronized print() method
public synchronized void print()
{
System.out.println(Thread.currentThread().getName() +
" wants to print");
// making sure that primary thread is getting suspended
if (Thread.currentThread().getName().equals("Primary Thread")) {
System.out.println("Primary Thread has been suspended");
Thread.currentThread().suspend();
System.out.println("Primary Thread has been resumed");
}
System.out.println(Thread.currentThread().getName()
+ " has finished printing");
}
}
// Custom Thread class that extends Thread class
class CustomThread extends Thread {
// string variable that will store name of the thread
Printer obj;
// constructor to initialize thread object
CustomThread(String name, Printer p)
{
// calling Thread class constructor and naming
// the thread
super(name);
obj = p;
}
// overridden run() method
public void run()
{
// calling synchronized print() method
obj.print();
// printing a statement that confirms the
// end of execution of the thread
System.out.println(this.getName() +
" has finished its execution");
}
}
// Driver class
class Deadlock {
// Main method which thros InterruptedException
// that can be caused as we are calling sleep() method
public static void main(String[] args) throws InterruptedException
{
// Creating Printer object in order to print
Printer p = new Printer();
// Creating primary thread and starting its execution
CustomThread primary_thread = new CustomThread("Primary Thread", p);
System.out.println("Primary Thread is starting its execution");
primary_thread.start();
// Making main thread to sleep for 1 second to make sure that
// primary thread executes print() method and goes into suspend state
Thread.sleep(2000);
// Creating secondary thread and starting its execution
CustomThread secondary_thread = new CustomThread("Secondary Thread", p);
System.out.println("Secondary Thread is starting its execution");
secondary_thread.start();
}
}
输出:
Primary Thread is starting its execution
Primary Thread wants to print
Primary Thread has been suspended
Secondary Thread is starting its execution
解释:
在上面的程序中,我们创建了两个线程,称为主线程和辅助线程,并在 2 秒的时间间隔后按各自的顺序启动两个线程。
主线程首先执行,并在执行 print() 方法时暂停。它拥有Printer 类对象的锁,同时保持挂起状态。之后,辅助线程尝试执行 print() 方法。但是它不能执行它,因为Printer 对象的锁是用primary 方法的。
在这个阶段,两个线程都进入死锁状态,程序执行永远不会结束。我们可以看到输出中只打印了4条语句,其余语句没有打印出来,因为程序执行进入了死锁状态。
参考:
- 多线程模型 – Oracle Docs
- 不推荐使用的线程方法 – Oracle Docs