什么是线程?
线程是操作系统能够进行运算调度的最小单元。每个进程(如一个Java应用程序)可以包含多个线程,线程之间共享进程的内存资源。
在Java中,线程由Thread类来表示,程序可以通过创建多个线程来同时执行多个任务。
创建线程的两种方式
1. 继承Thread类
通过继承Thread类并重写run()方法,可以创建一个新的线程。
class MyThread extends Thread {
public void run() {
System.out.println("Thread is running...");
}
}
public class Main {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); // 启动线程
}
}
在这个例子中,MyThread类继承了Thread类,并重写了run()方法。当调用start()方法时,线程启动并执行run()方法中的代码。
2. 实现Runnable接口
另一种更常用的方式是实现Runnable接口,将任务放在run()方法中,然后将其传递给Thread对象。
class MyRunnable implements Runnable {
public void run() {
System.out.println("Runnable thread is running...");
}
}
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start(); // 启动线程
}
}
这种方式更加灵活,因为Java不支持多继承,因此实现Runnable接口允许类保留继承其他类的能力。
线程生命周期
线程的生命周期主要有以下几个阶段:
- New(新建状态):线程被创建,但还未启动。
- Runnable(可运行状态):线程被启动,可以由操作系统调度执行。
- Blocked(阻塞状态):线程等待某些资源(如锁)时进入阻塞状态。
- Waiting(等待状态):线程等待另一个线程的通知时进入等待状态。
- Terminated(终止状态):线程执行完run()方法或因异常退出。
可以通过调用start()方法启动一个线程,而join()方法则用于等待线程的执行结束。
示例:线程的启动和结束
class MyRunnable implements Runnable {
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("Thread is running: " + i);
}
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new MyRunnable());
thread.start();
thread.join(); // 等待线程结束
System.out.println("Main thread finished.");
}
}
在这个示例中,thread.join()确保main线程会等待thread的执行完成后再继续。
线程同步
在多线程环境下,多个线程同时访问共享资源时可能会导致数据不一致的问题。为了解决这个问题,Java提供了同步机制。
同步方法和同步块
Synchronized关键字用于确保多个线程同时访问共享资源时,只有一个线程能够进入同步代码块
class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Count: " + counter.getCount());
}
}
在这个例子中,我们使用了synchronized方法来确保每次只有一个线程能够对count变量进行修改。如果不使用同步机制,可能会导致线程间竞争,结果不准确。
线程通信
Java提供了wait()、notify()和notifyAll()方法,用于在线程之间进行通信。这些方法通常与synchronized关键字一起使用,确保在多个线程协作时,线程能够按顺序执行。
class Message {
private String message;
public synchronized void produce(String msg) throws InterruptedException {
while (message != null) {
wait(); // 等待消息被消费
}
message = msg;
notify(); // 通知消费者线程
}
public synchronized String consume() throws InterruptedException {
while (message == null) {
wait(); // 等待生产者生产消息
}
String msg = message;
message = null;
notify(); // 通知生产者线程
return msg;
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
Message message = new Message();
Thread producer = new Thread(() -> {
try {
message.produce("Hello, World!");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread consumer = new Thread(() -> {
try {
System.out.println("Message: " + message.consume());
} catch (InterruptedException e) {
e.printStackTrace();
}
});
producer.start();
consumer.start();
producer.join();
consumer.join();
}
}
在这个示例中,produce()方法用于生成消息,而consume()方法用于消费消息。wait()方法让线程进入等待状态,notify()方法则唤醒相应的线程进行操作。
本篇文章介绍了Java中的多线程编程基础,详细讲解了如何创建线程、管理线程生命周期、以及如何处理线程同步和线程通信。在实际开发中,多线程可以显著提升程序的性能,但也需要注意线程之间的同步问题,避免出现数据竞争等问题。
有兴趣的小伙伴可以关注我的公众号【知识星球站】一起讨论学习!!

822

被折叠的 条评论
为什么被折叠?



