本文讲述了线程的故事,并解释了线程的主要优点,缺点和用法。 您将向熟练的Java程序员学习如何使用Extends Thread类和Implements Runnable接口创建线程。
- 减少开发时间。
- 降低维护成本。
- 提高复杂应用程序的性能。
- 对于提高用户界面的响应速度很有用。
- 用于服务器应用程序以提高高吞吐量和资源利用率。
- 并行任务。
- 如果一个线程不能使用CPU的所有计算资源(因为指令取决于彼此的结果),则运行另一个线程可以避免使这些空闲。
- 利用多处理器系统
- 共享硬件资源(例如缓存或转换后备缓冲区(TLB))时,多个线程可能会相互干扰。
- 即使只有一个线程正在执行,单个线程的执行时间也会降低。 这是由于较慢的频率和/或容纳线程交换硬件所需的其他流水线级。
- 软件对多线程的硬件支持更加明显,因此与多处理相比,需要对应用程序和操作系统进行更多更改。
- Java应用程序是自然线程化的。 运行时环境通过 一个线程中 的 main() 方法 开始执行程序 。 垃圾回收发生在另一个线程中。 屏幕更新发生在第三个线程中。 可能还会运行其他线程,这些线程主要与虚拟机的行为有关。 所有这些对程序员来说都是无形的。 有时您只关心主线程中发生的事情,该主线程包括程序的 main() 方法。 在这种情况下,您可能根本不必担心线程。
- 多线程的主要目的是提供程序的两个或更多部分的同时执行,以尽可能多地利用CPU时间。 多线程程序包含两个或多个可以同时运行的部分。 这种程序的每个部分都称为线程。 每个线程都有一个单独的执行路径。 这样,单个程序可以同时执行两个或多个任务。
- 线程是轻量级进程。 它们共享相同的地址空间。 在多线程环境中,程序会最大程度地利用CPU,以便 空闲时间可以保持最小。
- 执行异步或后台处理。
还请参见: 线程魔术技巧:Java线程可以做的5件事
Thread类是程序中的执行线程。 Java虚拟机允许应用程序具有多个并行运行的执行线程。 最重要的几点可以在下面找到:
- 每个线程都有一个优先级。 优先级较高的线程先于优先级较低的线程执行
- 每个线程可能会也可能不会被标记为守护程序。
- 有两种方法可以创建新的执行线程。 一种是将一个类声明为Thread的子类。
- 创建线程的另一种方法是声明一个实现Runnable接口的类。
线程类提供了用于在线程类上创建和执行操作的构造函数和方法。 线程类扩展了Object类并实现了Runnable接口。
1.线程()
2.线程( String str )
3.线程( Runnable r )
4.线程( Runnable r , 字符串str )
线程类定义了许多用于管理线程的方法。 他们之中有一些是:
方法 | 描述 |
setName() | 给线程起个名字 |
getName() | 返回线程的名称 |
getPriority() | 返回线程的优先级 |
活着() | 检查线程是否仍在运行 |
加入() | 等待线程结束 |
跑() | 线程的入口点 |
睡觉() | 将线程挂起指定的时间 |
开始() | 通过调用run()方法启动线程 |
- 扩展线程类
- 实现Runnable接口
通过扩展 Thread 类 的新类创建线程, 并创建该类的实例。 扩展类必须重写 run() 方法,该方法是新线程的入口点。
public class MyThread extends Thread{
public void run()
{
System.out.println("Thread started running..");
}
public static void main( String args[] )
{
MyThread mt = new MyThread();
mt.start();
}
}
输出:
线程开始运行。
在这种情况下,我们必须重写 run() ,然后使用 start() 方法启动并运行线程。 同样,当您创建MyThread类对象时,由于它是超类,因此也将调用Thread类构造函数,因此MyThread类对象充当Thread类对象。
我们直接调用run()方法,而无需使用start()方法
public static void main(String args[])
{
MyThread mt = new MyThread();
mt.run();
}
不会为该线程分配新的调用堆栈,它将开始在当前调用堆栈(即 主 线程 的调用堆栈)中运行 。 因此,多线程将不存在。
我们启动一个线程两次
线程不能启动两次。 如果尝试这样做, 将抛出 IllegalThreadStateException 。
public static void main( String args[] )
{
MyThread mt = new MyThread();
mt.start();
mt.start(); //Exception thrown
}
当线程处于运行状态时,您尝试再次启动它,或者任何方法尝试使用 start() 方法 再次调用该线程 ,都会引发异常。
创建线程的最简单方法是创建一个实现可运行接口的类。 在实现runnable接口之后,该类需要实现 run() 方法,即
公共无效run()
- run()方法将并发线程引入程序。 当run()返回时,该线程将结束。
- 您必须在run()方法中为线程指定代码。
- run()方法可以调用其他方法,可以使用其他类并声明变量,就像其他任何普通方法一样。
MyThread 类 实现 Runnable {
public void run() {
System.out.println("Thread started running..");
}
public static void main(String args[]) {
MyThread mt = new MyThread();
Thread t = new Thread(mt);
t.start();
}
}
输出:
线程开始运行。
要调用 run() 方法,请使用 start() 方法。 调用start()时,将向线程提供一个新的堆栈,并调用run()方法将新线程引入程序中。
线程由于以下原因而结束:
- 当run()方法完成执行时,线程结束。
- 当线程抛出程序中未捕获的异常或错误时。
- Java程序完成或结束。
- 另一个线程调用stop()方法。
- 在多个线程尝试访问共享资源时,我们需要确保一次只能由一个线程使用资源。 实现此目标的过程称为 同步 。
- Java中的sync关键字创建称为关键部分的代码块。
- 通过使用此方法,一次只能有一个线程访问该方法,并且第二个调用将被阻塞,直到第一个调用返回或在同步方法内部调用了wait()为止。
synchronized (object) {
// Statement to be synchronized
}
- 如果我们不使用同步,而让两个或多个线程同时访问共享资源,则会导致结果失真。
- 这是一个示例:假设我们有两个不同的线程 T1 和 T2 ,T1开始执行并将某些值保存在文件 sample.txt中 , 该文件 将在T1返回时用于计算一些结果。 同时,T2开始,在T1返回之前,T2更改T1保存在文件sample.txt中的值( sample .txt是共享资源)。 现在显然T1将给出错误的结果。
- 引入了同步以防止此类问题的发生。 如果在上述情况下使用同步,则一旦T1开始使用 sample.txt 文件,该文件将被 锁定 (锁定模式),直到T1返回之前,其他线程都无法访问或修改它。
- 死锁描述了一种情况,其中两个或多个线程永远被阻塞,互相等待。 当多个线程需要相同的锁但以不同的顺序获得它们时,就会发生死锁。 Java多线程程序可能会遇到死锁情况,因为 synced 关键字会导致正在执行的线程在等待与指定对象关联的锁或监视器时阻塞。
- 为了避免死锁,应该确保当您获取多个锁时,始终在所有线程中以相同顺序获取锁。
Java程序员在这里讨论的 有关 Thread的 每件事 都旨在使您了解Thread及其用法以及缺点和好处。