Java多线程的用法详解
Java多线程是Java编程中非常重要的一个部分,在Java中通过多线程实现并发编程,提高程序的执行效率与响应能力,本文将详细讲解Java多线程的用法。
为什么需要多线程?
在介绍Java多线程之前,我们需要了解为什么需要多线程。首先,操作系统分给每个进程固定的资源是有限的,而非多线程的单进程只能利用其中一个CPU并执行一个任务。而多线程的程序可以分裂成许多子任务且各自独立执行,可充分利用CPU时间片,从而提高CPU的利用率,加速程序的执行。
另外,一些需要处理的操作是耗时且独立的,例如:读写文件或接收网络请求等,这些操作使用单线程,将导致程序在等待这些操作完成时阻塞,从而浪费CPU资源。而使用多线程,可以充分利用CPU的其他资源,提高程序的效率。
Java多线程的用法
Java通过封装实现了多线程,并提供了许多API来支持多线程编程。
创建线程
Java中线程的创建方式有两种:
- 继承Thread类
- 实现Runnable接口
继承Thread类
class MyThread extends Thread {
public void run() {
System.out.println("这是一个新线程!");
}
}
public class ThreadDemo {
public static void main(String[] args) {
MyThread myThread = new MyThread(); // 创建一个新线程
myThread.start(); // 启动线程
System.out.println(Thread.currentThread().getName() + "线程已结束。");
}
}
输出:
这是一个新线程!
main线程已结束。
实现Runnable接口
class MyRunnable implements Runnable {
public void run() {
System.out.println("这是一个新线程!");
}
}
public class RunnableDemo {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable(); // 创建一个Runnable对象
Thread thread = new Thread(myRunnable); // 创建一个新线程
thread.start(); // 启动线程
System.out.println(Thread.currentThread().getName() + "线程已结束。");
}
}
输出:
这是一个新线程!
main线程已结束。
线程的生命周期
Java中的线程生命周期可分为以下五个状态:
- 新建状态(New):新创建了一个线程对象。
- 就绪状态(Runnable):线程创建后,其他线程调用了该线程的 start() 方法,该线程进入就绪状态。
- 运行状态(Running):就绪状态的线程获得 CPU 时间,执行 run() 方法。
- 阻塞状态(Blocked):阻塞状态指线程因为某种原因放弃了 CPU 的使用权,暂时停止运行,直到线程进入就绪或结束状态。例如:等待IO操作、调用 sleep() 方法等。
- 结束状态(Dead):线程执行完了 run() 方法,或因异常退出了 run() 方法,该线程结束生命周期。
线程调度
Java提供了一些 API 来实现线程的调度。
sleep()
sleep() 方法可以让一个线程暂停执行,进入阻塞状态。它有两个重载方法,分别是:
public static void sleep(long millis) throws InterruptedException
public static void sleep(long millis, int nanos) throws InterruptedException
第一个方法指挂起线程 ms 时间,第二个方法指挂起线程 ms 毫秒 + ns 纳秒时间。需要注意的是这两个方法会抛出的是 InterruptedException 异常,需要通过 try-catch 语句捕获。
public class SleepDemo {
public static void main(String[] args) {
try {
System.out.println("开始执行");
Thread.sleep(3000); // 线程休眠3秒
System.out.println("结束执行");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出:
开始执行
// 等待3秒时间
结束执行
yield()
yield() 方法可以让当前线程让出 CPU 时间片,进行调度。调度器可能会决定将 CPU 时间片分配给这个线程下一次调用。
public class YieldDemo {
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("线程1执行:" + i);
Thread.yield(); // 让出 CPU 调度
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("线程2执行:" + i);
}
});
thread1.start();
thread2.start();
}
}
输出:
线程1执行:0
线程2执行:0
线程1执行:1
线程2执行:1
线程1执行:2
线程2执行:2
线程1执行:3
线程2执行:3
线程1执行:4
线程2执行:4
join()
join() 方法可以让一个线程等待另一个线程执行结束。假设当前线程 A 执行了 threadB.join(),则当前线程 A 将进入阻塞状态,直到 threadB 线程执行结束。
public class JoinDemo {
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(() -> {
System.out.println("线程1开始执行:");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程1结束执行:");
});
Thread thread2 = new Thread(() -> {
System.out.println("线程2开始执行:");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程2结束执行:");
});
thread1.start(); // 启动线程1
thread2.start(); // 启动线程2
thread1.join(); // 等待线程1结束
thread2.join(); // 等待线程2结束
System.out.println("所有线程执行结束。");
}
}
输出:
线程1开始执行:
线程2开始执行:
线程2结束执行:
线程1结束执行:
所有线程执行结束。
线程同步
多线程在同时访问共享资源时可能会出现数据冲突的情况,这时就需要使用线程同步来保证线程安全。
synchronized关键字
synchronized 关键字可用于修饰一个方法或代码块,当其它线程想要访问该代码块时,必须先获得相应的锁。如果该锁被其它线程占用,则需要等待直到该线程释放锁。
public class SynchronizedDemo {
private volatile static int COUNT = 0;
private static Object lock = new Object();
private static void increment() {
synchronized (lock) {
COUNT++;
}
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
increment();
}).start();
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("COUNT = " + COUNT);
}
}
输出:
COUNT = 100
Lock接口
Java提供了Lock接口实现线程同步,它比synchronized更加灵活,可适用于复杂场景。
public class LockDemo {
private volatile static int COUNT = 0;
private static Lock lock = new ReentrantLock();
private static void increment() {
lock.lock();
try {
COUNT++;
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
increment();
}).start();
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("COUNT = " + COUNT);
}
}
输出:
COUNT = 100
总结
本文详细介绍了Java多线程的用法,包括线程创建、线程的生命周期、线程调度和线程同步。希望通过本文的学习,能够有助于对Java多线程的理解和运用。
示例
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java多线程的用法详解 - Python技术站