Java中的多线程基础
在Java编程语言中,多线程是一种允许程序同时执行多个任务的技术。理解并行与并发的概念对于有效利用多线程至关重要:
并行与并发
并行是指多个处理单元同时进行计算,即多个事件在同一时间点上发生。而并发则是指多个任务在一段时间内交替执行,虽然它们可能不是同时运行,但在宏观上看起来是同时进行的。
实现多线程的方法
1. 通过继承Thread类:创建一个新的类继承自Thread类,并重写其run方法来定义线程的具体行为。
2. 实现Runnable接口:让一个类实现Runnable接口,然后将其实例作为参数传递给Thread类的构造器,通过调用Thread的start方法来启动线程。
3. 使用Callable接口与FutureTask:与Runnable类似,但Callable可以返回结果并且可以抛出异常,适合需要返回值的任务。
Thread类常用方法介绍
- void start()
: 启动线程,使线程进入就绪状态,等待CPU调度执行。
- void run()
: 定义线程的执行体,当线程被调度时会执行此方法中的代码。
- String getName()
: 获取线程的名字。
- void setName(String name)
: 设置线程的名字。
案例分析
案例1:两个线程轮流打印数字至100
此示例展示了如何使用同步机制(synchronized关键字)确保两个线程按顺序打印数字,直到达到100为止。
package com.example.multithreading;
public class NumberPrinter extends Thread {
private static final Object lock = new Object();
private static int number = 1;
@Override
public void run() {
while (number <= 100) {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + ": " + number);
number++;
lock.notify();
if (number <= 100) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) {
NumberPrinter printer1 = new NumberPrinter();
NumberPrinter printer2 = new NumberPrinter();
printer1.setName("Printer1");
printer2.setName("Printer2");
printer1.start();
printer2.start();
}
}
案例2:三个售票窗口同时售票
本案例通过实现Runnable接口的方式,模拟了三个售票窗口同时销售有限数量的车票过程,确保了线程安全和资源的正确分配。
package com.example.multithreading;
public class TicketSeller implements Runnable {
private static int tickets = 18; // 假设有18张票
private static final Object lock = new Object();
@Override
public void run() {
while (tickets > 0) {
synchronized (lock) {
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + ": 售出一张票,剩余票数: " + (--tickets));
} else {
System.out.println(Thread.currentThread().getName() + ": 票已售罄!");
}
}
try {
Thread.sleep(1000); // 模拟售票时间
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Thread window1 = new Thread(new TicketSeller(), "窗口1");
Thread window2 = new Thread(new TicketSeller(), "窗口2");
Thread window3 = new Thread(new TicketSeller(), "窗口3");
window1.start();
window2.start();
window3.start();
}
}