使用Java线程的关键在于:创建线程、启动线程、管理线程生命周期、实现同步、处理线程间通信。 其中,创建线程可以通过继承Thread
类或实现Runnable
接口来实现。启动线程后,需要注意线程的管理和生命周期控制,例如使用join
方法等待线程结束,使用synchronized
关键字或锁机制实现线程同步。此外,线程间通信可以通过wait
、notify
和notifyAll
方法来实现。
一、创建线程
创建线程是使用Java线程的第一步,Java提供了两种主要方法来创建线程:
1、继承Thread类
通过继承Thread
类来创建线程是最简单的方法之一。你需要创建一个新的类并继承Thread
类,然后覆盖run
方法。run
方法包含线程的任务代码。
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("Thread is running");
}
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
}
}
2、实现Runnable接口
实现Runnable
接口是更灵活和常用的方法。你需要创建一个实现Runnable
接口的类,并将任务代码放在run
方法中。然后将该类的实例传递给Thread
对象并启动线程。
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Thread is running");
}
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start();
}
}
二、启动线程
启动线程是通过调用Thread
类的start
方法来完成的。调用start
方法将会导致Java虚拟机调用线程的run
方法。注意不要直接调用run
方法,否则它只是普通的方法调用,不会启动新线程。
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Thread is running");
}
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start();
}
}
三、管理线程生命周期
线程的生命周期分为新建、就绪、运行、阻塞和死亡五种状态。理解和管理线程的生命周期对于编写健壮的多线程应用程序非常重要。
1、线程状态
- 新建(New): 当线程对象创建后,就进入了新建状态。
- 就绪(Runnable): 当调用
start
方法后,线程进入就绪状态,等待被CPU调度。 - 运行(Running): 线程获得CPU资源后进入运行状态,执行其任务。
- 阻塞(Blocked): 线程在等待某些条件(如I/O操作、锁)时进入阻塞状态。
- 死亡(Dead): 线程执行完
run
方法或因异常退出,则进入死亡状态。
2、线程休眠
可以使用Thread
类的sleep
方法让线程休眠一段时间,从而让出CPU资源给其他线程。
public class MyRunnable implements Runnable {
@Override
public void run() {
try {
Thread.sleep(1000); // 线程休眠1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread is running after sleep");
}
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start();
}
}
3、等待线程结束
可以使用Thread
类的join
方法等待线程执行结束。
public class MyRunnable implements Runnable {
@Override
public void run() {
try {
Thread.sleep(1000); // 线程休眠1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread is running after sleep");
}
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start();
try {
thread.join(); // 等待线程执行结束
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Main thread continues after child thread finishes");
}
}
四、实现同步
在多线程环境中,同步是防止多个线程同时访问共享资源的关键,避免数据不一致或竞争条件。Java提供了多种同步机制,如synchronized
关键字和Lock
接口。
1、synchronized关键字
synchronized
关键字可以用来修饰方法或代码块,以实现同步。
public class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
public static void main(String[] args) {
Counter counter = new Counter();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
};
Thread thread1 = new Thread(task);
Thread thread2 = new Thread(task);
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Final count: " + counter.getCount());
}
}
2、使用Lock接口
Lock
接口提供了更灵活的锁机制,可以替代synchronized
关键字。ReentrantLock
是Lock
接口的一个常用实现。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Counter {
private int count = 0;
private final Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public int getCount() {
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
Counter counter = new Counter();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
};
Thread thread1 = new Thread(task);
Thread thread2 = new Thread(task);
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Final count: " + counter.getCount());
}
}
五、处理线程间通信
线程间通信是指多个线程之间交换数据或信号,以协调它们的工作。Java提供了wait
、notify
和notifyAll
方法来实现线程间通信。
1、wait和notify
wait
方法使线程等待,直到其他线程调用notify
或notifyAll
方法。
public class SharedResource {
private int data;
private boolean available = false;
public synchronized void produce(int data) {
while (available) {
try {
wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
this.data = data;
available = true;
notifyAll();
}
public synchronized int consume() {
while (!available) {
try {
wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
available = false;
notifyAll();
return data;
}
public static void main(String[] args) {
SharedResource resource = new SharedResource();
Runnable producer = () -> {
for (int i = 0; i < 10; i++) {
resource.produce(i);
System.out.println("Produced: " + i);
}
};
Runnable consumer = () -> {
for (int i = 0; i < 10; i++) {
int data = resource.consume();
System.out.println("Consumed: " + data);
}
};
Thread producerThread = new Thread(producer);
Thread consumerThread = new Thread(consumer);
producerThread.start();
consumerThread.start();
}
}
2、使用Condition对象
Condition
对象是Lock
接口的一个重要部分,提供了更高级的线程间通信机制。
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SharedResource {
private int data;
private boolean available = false;
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
public void produce(int data) {
lock.lock();
try {
while (available) {
condition.await();
}
this.data = data;
available = true;
condition.signalAll();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
}
public int consume() {
lock.lock();
try {
while (!available) {
condition.await();
}
available = false;
condition.signalAll();
return data;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return -1;
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
SharedResource resource = new SharedResource();
Runnable producer = () -> {
for (int i = 0; i < 10; i++) {
resource.produce(i);
System.out.println("Produced: " + i);
}
};
Runnable consumer = () -> {
for (int i = 0; i < 10; i++) {
int data = resource.consume();
System.out.println("Consumed: " + data);
}
};
Thread producerThread = new Thread(producer);
Thread consumerThread = new Thread(consumer);
producerThread.start();
consumerThread.start();
}
}
六、线程池的使用
线程池是一种管理和复用线程资源的机制,可以减少线程创建和销毁的开销,提高应用程序性能。Java提供了Executor
框架来实现线程池。
1、创建线程池
可以使用Executors
类提供的工厂方法创建不同类型的线程池。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
Runnable task = () -> {
System.out.println("Thread: " + Thread.currentThread().getName());
};
executor.execute(task);
}
executor.shutdown();
}
}
2、管理线程池
ExecutorService
提供了多种方法来管理线程池,如shutdown
、shutdownNow
和awaitTermination
等。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
Runnable task = () -> {
System.out.println("Thread: " + Thread.currentThread().getName());
};
executor.execute(task);
}
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
}
}
七、使用并发集合
并发集合类是线程安全的集合类,适用于多线程环境。Java提供了多种并发集合类,如ConcurrentHashMap
、CopyOnWriteArrayList
和BlockingQueue
等。
1、ConcurrentHashMap
ConcurrentHashMap
是线程安全的哈希表,适用于高并发环境。
import java.util.concurrent.ConcurrentHashMap;
public class ConcurrentHashMapExample {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
Runnable task = () -> {
for (int i = 0; i < 10; i++) {
map.put(Thread.currentThread().getName() + " - " + i, i);
}
};
Thread thread1 = new Thread(task);
Thread thread2 = new Thread(task);
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
map.forEach((key, value) -> System.out.println(key + ": " + value));
}
}
2、BlockingQueue
BlockingQueue
是线程安全的队列,支持阻塞操作,适用于生产者-消费者模式。
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class BlockingQueueExample {
public static void main(String[] args) {
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);
Runnable producer = () -> {
for (int i = 0; i < 10; i++) {
try {
queue.put(i);
System.out.println("Produced: " + i);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
};
Runnable consumer = () -> {
for (int i = 0; i < 10; i++) {
try {
int data = queue.take();
System.out.println("Consumed: " + data);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
};
Thread producerThread = new Thread(producer);
Thread consumerThread = new Thread(consumer);
producerThread.start();
consumerThread.start();
}
}
八、使用Future和Callable
Future
和Callable
接口提供了一种获取异步任务结果的方法。
1、Callable接口
Callable
接口类似于Runnable
接口,但它可以返回结果或抛出异常。
import java.util.concurrent.Callable;
public class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
return 123;
}
public static void main(String[] args) {
MyCallable callable = new MyCallable();
try {
Integer result = callable.call();
System.out.println("Result: " + result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
2、Future接口
Future
接口用于表示异步计算的结果,可以使用ExecutorService
的submit
方法提交Callable
任务,并获取Future
对象。
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class FutureExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
Callable<Integer> task = () -> {
Thread.sleep(1000);
return 123;
};
Future<Integer> future = executor.submit(task);
try {
Integer result = future.get();
System.out.println("Result: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
executor.shutdown();
}
}
九、使用同步辅助类
同步辅助类是用于协调多个线程的工具,Java提供了多种同步辅助类,如CountDownLatch
、CyclicBarrier
和Semaphore
等。
1、CountDownLatch
CountDownLatch
允许一个或多个线程等待,直到其他线程完成一组操作。
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) {
CountDownLatch latch = new CountDownLatch(3);
Runnable task = () -> {
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " finished");
latch.countDown();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
};
for (int i = 0; i < 3; i++) {
new Thread(task).start();
}
try {
latch.await();
System.out.println("All tasks finished");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
2、CyclicBarrier
CyclicBarrier
允许一组线程互相等待,直到到达一个公共屏障点。
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierExample {
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(3, () -> System.out.println("All parties arrived"));
Runnable task = () -> {
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " reached barrier");
barrier.await();
System.out.println(Thread.currentThread().getName() + " continues");
} catch (InterruptedException | BrokenBarrierException e) {
Thread.currentThread().interrupt();
}
};
for (int i = 0; i < 3; i++) {
new Thread(task).start();
}
}
}
3、Semaphore
Semaphore
控制对共享资源的访问,允许多个线程同时访问。
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);
Runnable task = () -> {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + " acquired semaphore");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " releasing semaphore");
semaphore.release();
} catch (InterruptedException e) {
相关问答FAQs:
1. 什么是Java线程,如何使用它?
Java线程是用于实现并发执行的一种机制。它允许程序同时执行多个任务,提高系统的响应性和效率。要使用Java线程,可以创建一个继承Thread类的子类,并重写run()方法来定义线程要执行的任务,然后通过调用start()方法来启动线程。
2. 如何创建和启动一个Java线程?
要创建一个Java线程,可以通过创建Thread类的实例,并传递一个Runnable对象给Thread类的构造函数。然后,调用Thread类的start()方法来启动线程。线程一旦启动,会自动调用Runnable对象的run()方法来执行线程任务。
3. 如何控制Java线程的执行顺序和优先级?
可以使用Thread类提供的方法来控制Java线程的执行顺序和优先级。例如,可以使用sleep()方法来暂停线程的执行一段时间,使用join()方法来等待其他线程执行完毕,使用yield()方法来让出CPU资源给其他线程,使用setPriority()方法来设置线程的优先级等。通过合理地使用这些方法,可以实现线程的有序执行和优先级调度。
注意:在使用Java线程时,需要注意线程间的同步和互斥,以避免出现竞态条件和数据不一致的问题。可以使用synchronized关键字或Lock对象来实现线程的同步和互斥。
原创文章,作者:Edit2,如若转载,请注明出处:https://docs.pingcode.com/baike/173105