多线程
引题:什么是多线程
多线程就是同一时间做好多事情,比如有一个词叫:一边一边,一边吃饭一边看电视......等等,这样在程序上有什么好处呢?提高了程序的工作效率,让程序实现的更多的东西:比如多人游戏,比如订单服务,这个如果使用单线程一个一个处理那就会花费很长时间,多线程处理就相当于多加了几条生产线来完成任务.....
介绍:
多线程是指在一个程序中同时运行多个独立的线程,每个线程执行相对独立的任务。Java是一种支持多线程编程的语言,它通过java.lang.Thread
类和java.lang.Runnable
接口提供了多线程的支持。以下是关于Java多线程的一些基本概念和用法:
1. 线程的创建和启动:
在Java中,有两种主要创建线程的方式:
-
继承Thread类:
class MyThread extends Thread { public void run() { // 线程执行的代码 } } // 创建并启动线程 MyThread myThread = new MyThread(); myThread.start(); }
-
实现Runnable接口:
-
Runnable接口应该由任何类实现,这些类的实例打算由线程执行。类必须定义一个名为run的无参数方法。该接口旨在为希望在活动状态下执行代码的对象提供公共协议。例如,Runnable是由Thread类实现的。处于活动状态仅仅意味着线程已经启动并且尚未停止。此外,Runnable提供了在不子类化Thread的情况下使类处于活动状态的方法。实现Runnable的类可以在不子类化Thread by的情况下运行
class MyRunnable implements Runnable { public void run() { // 线程执行的代码 } } // 创建Thread对象,并传入实现了Runnable接口的对象 Thread myThread = new Thread(new MyRunnable()); myThread.start(); }
2. 线程的生命周期:
-
新建状态(New): 创建了一个线程对象,但还没有调用
start()
方法。 -
就绪状态(Runnable): 线程调用
start()
方法后,等待获取CPU执行时间。 -
运行状态(Running): 获取到CPU执行时间,开始执行
run()
方法。 -
阻塞状态(Blocked): 线程被暂时挂起,例如等待某个资源。
-
终止状态(Terminated): 线程执行完成或者因异常退出。
3. 线程同步和互斥:
多线程可能导致资源的竞争和不确定性行为。Java提供了synchronized
关键字和Lock
接口来实现线程的同步和互斥。关键代码块或者方法可以被标记为synchronized
,确保在同一时刻只有一个线程能够访问:
class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
}
4. 线程通信:
多个线程之间可能需要协调和通信。Java提供了wait()
, notify()
, 和 notifyAll()
等方法来实现线程之间的通信。
class Message {
private String message;
public synchronized void setMessage(String message) {
this.message = message;
notify(); // 通知等待的线程
}
public synchronized String getMessage() throws InterruptedException {
while (message == null) {
wait(); // 等待消息
}
return message;
}
}
5. 线程池:
线程池是一种用于管理和重用线程的机制。通过使用线程池,可以减少线程的创建和销毁的开销,提高性能。Java中的Executor
框架提供了线程池的实现。
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.execute(new MyRunnable());
executor.shutdown(); // 关闭线程池
6. ThreadLocal:
ThreadLocal
类用于在多线程环境下保持变量的局部性,每个线程都有自己的副本。这对于需要在线程之间独立管理变量的情况很有用。
ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
threadLocal.set(42);
int value = threadLocal.get();
7. 并发集合类:
Java提供了一系列的并发集合类,如ConcurrentHashMap
、CopyOnWriteArrayList
等,用于在多线程环境中安全地访问集合。
Map<String, String> concurrentMap = new ConcurrentHashMap<>();
List<String> copyOnWriteList = new CopyOnWriteArrayList<>();
8. 原子操作:
java.util.concurrent.atomic
包提供了一系列原子类,用于在不使用锁的情况下进行原子操作。
AtomicInteger atomicInteger = new AtomicInteger(0);
int result = atomicInteger.incrementAndGet();
9. 并发工具类:
Java还提供了一些并发工具类,如CountDownLatch
、CyclicBarrier
、Semaphore
等,用于实现更复杂的线程协作。
CountDownLatch latch = new CountDownLatch(3); // ... // 在某处调用 latch.countDown(); // ... latch.await(); // 等待直到计数器减为零
多线程编程是一个广阔而复杂的主题,需要小心设计和实现以避免竞态条件、死锁等问题。 Java提供的工具和类库旨在帮助开发者创建安全且高效的多线程应用程序。
线程礼让:
在Java中,线程礼让是通过 `Thread.yield()` 方法实现的。线程礼让的目的是让当前正在执行的线程让出CPU时间片,让其他线程有机会执行。它并不是强制性的,仅仅是一种建议,JVM可以选择忽略这个建议。
线程礼让的使用场景可能是为了提高程序的执行效率或是更好地实现线程之间的合作。在某些情况下,一个线程可能会比其他线程更重要,为了避免线程的饥饿现象,它可以选择礼让其他线程。
下面是一个简单的例子:
public class ThreadYieldExample {
public static void main(String[] args) {
Thread t1 = new Thread(new MyRunnable(), "Thread 1");
Thread t2 = new Thread(new MyRunnable(), "Thread 2");
t1.start();
t2.start();
}
static class MyRunnable implements Runnable {
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
// 在每次循环迭代时,线程礼让
Thread.yield();
}
}
}
}
在上面的例子中,两个线程(Thread 1 和 Thread 2)共享一个`Runnable`实例。在每次循环迭代时,线程使用 `Thread.yield()` 语句礼让CPU时间片,从而给其他线程执行的机会。
需要注意的是,线程礼让并不是一种通用的解决方案,而是在特定情况下使用的一种手段。过度使用 `yield` 可能会导致线程切换频繁,从而降低程序的整体性能。在实际应用中,更好的方式是通过合适的同步和协作机制来实现线程之间的协调。