#线程基本概念和使用方法#
-
线程的定义和作用
- 线程是操作系统能够进行运算调度的最小单位(程序执行的最小单元),它被包含在进程之中,是进程中实际运行的实体
- 线程的创建
- 继承Thread类并重写run方法
- 实现Runable接口并实现run方法,然后传给Thread对象
- 实现Callable<T>接口并实现call方法
package com.msq.pattern.thread;
import java.util.concurrent.*;
public class ThreadCreateDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 1.继承thread类
// 1.1新建一个线程
MyThread myThread = new MyThread();
// 1.2调用start方法开启这个线程
myThread.start();
// 2. 实现runnable接口
// 2.1将Runnable实现类的实例传递给Thread类的构造器,创建线程对象。
Thread thread = new Thread(new MyThread2());
// 2.2调用线程对象的start()方法启动线程。
thread.start();
// 3,实现callable<T>接口,T 返回值类型
MyThread3 myThread3 = new MyThread3();
// 3.1 通过ExecutorService提交Callable任务,并返回一个Future对象。
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<String> submit = executorService.submit(myThread3);
// 3.2使用Future对象来获取任务的结果。
// 等待结果并获取
System.out.println("result:"+submit.get());
executorService.shutdown();
//---------------
Callable<String> task = () -> {
return "result";
};
Thread task1 = new Thread(()-> {
System.out.println("result");
});
ExecutorService executor = Executors.newFixedThreadPool(10); // 创建固定大小的线程池
executor.execute(new MyThread());
ExecutorService executor1 = Executors.newCachedThreadPool(); // 创建可缓存的线程池
executor.submit(() -> {
// 线程执行的代码
});
}
// 实现Callable接口。
static class MyThread3 implements Callable<String>{
@Override
public String call() throws Exception {
return "result";
}
}
// 实现Runnable接口。
static class MyThread2 implements Runnable{
@Override
public void run() {
System.out.println("线程执行的代码:实现接口");
}
}
// 继承thread类,重写run方法
static class MyThread extends Thread{
@Override
public void run() {
System.out.println("线程运行的代码,继承类");
}
}
}
- 线程的基本属性和方法
-
线程属性:
- Name - 线程的名称,可以通过
getName()
获取,setName(String name)
设置。 - Priority - 线程的优先级,可以通过
getPriority()
获取,setPriority(int priority)
设置。优先级范围是1到10。 - Thread Group - 线程所属的线程组,可以通过
getThreadGroup()
获取。 - Daemon Status - 守护线程状态,守护线程可以在用户线程执行完毕之后结束,通过
isDaemon()
检查,setDaemon(boolean on)
设置。 - State - 线程的状态,如新建、就绪、运行、阻塞、等待、超时等待、终止等,可以通过
getState()
获取。
- Name - 线程的名称,可以通过
-
线程方法:
- start() - 启动线程,使得线程进入就绪状态。
- run() - 包含线程执行的代码,可以被重写。
- join() - 等待该线程终止。
- sleep(long millis) - 使当前线程暂停执行指定的时间。
- interrupt() - 中断线程,设置中断状态。
- 调用线程的
interrupt()
方法会将该线程的中断状态设置为true
。 - 这个方法不会立即停止线程正在执行的操作,而是提供一个信号,表明线程应该在合适的时候停止。
InterruptedException
,当线程处于等待、休眠或其他一些特定状态时,如果此时线程的中断状态被设置为true
,那么这些特定的方法会抛出InterruptedException。
可以使用
volatile或者原子类自己判断是否要中断(结束)- 守护线程(Daemon thread)不会阻止JVM退出。即使守护线程正在运行,JVM也会在所有非守护线程结束时退出。
- 调用线程的
- isInterrupted() - 检查当前线程是否被中断。
- currentThread() - 返回执行当前代码的线程对象。
- yield() - 暂停当前线程对象的执行,让其他同优先级的线程有机会执行。
- setName(String name) - 设置线程的名字。
- getName() - 获取线程的名字。
- setPriority(int priority) - 设置线程的优先级。
- getPriority() - 获取线程的优先级。
- setDaemon(boolean on) - 将线程设置为守护线程或用户线程。
- isDaemon() - 检查线程是否是守护线程。
- getThreadGroup() - 获取线程所属的线程组。
- getState() - 返回线程的状态。
- toString() - 返回线程的字符串表示,通常包含线程名称、优先级和线程ID。
-
Thread thread = new Thread(() -> {
// 线程执行的代码
});
// 获取和设置线程名称
String name = thread.getName();
thread.setName("MyThread");
// 获取和设置线程优先级
int priority = thread.getPriority();
thread.setPriority(Thread.MAX_PRIORITY);
// 启动线程
thread.start();
// 等待线程终止
try {
thread.join();
} catch (InterruptedException e) {
// 线程中断异常处理
}
// 检查线程是否为守护线程
boolean isDaemon = thread.isDaemon();
thread.setDaemon(true);
线程中断的列子:
public class InterruptibleTask implements Runnable {
private volatile boolean running = true;
@Override
public void run() {
System.out.println("任务开始执行,线程名称:" + Thread.currentThread().getName());
try {
while (running) {
// 模拟业务逻辑处理
System.out.println("任务正在执行...");
// 假设业务逻辑需要一些时间来完成
Thread.sleep(1000);
// 检查中断状态,如果线程被中断,跳出循环
if (Thread.currentThread().isInterrupted()) {
System.out.println("检测到中断信号,准备退出循环。");
break;
}
}
} catch (InterruptedException e) {
// 捕获到InterruptedException,说明线程在等待时被中断
System.out.println("在等待时被中断,准备退出循环。");
// 清除中断状态,以便后续操作可以使用interrupt()再次中断
Thread.currentThread().interrupt();
} finally {
// 清理资源
cleanUp();
}
System.out.println("任务执行完毕,线程名称:" + Thread.currentThread().getName());
}
// 模拟清理资源的方法
private void cleanUp() {
running = false;
System.out.println("资源清理完成。");
}
// 主方法,用于启动线程并演示中断
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new InterruptibleTask());
thread.start();
// 让主线程睡眠一会儿,以便任务线程有时间执行
Thread.sleep(3000);
// 中断任务线程
thread.interrupt();
// 等待任务线程完成
thread.join();
}
}
#进程和线程的区别#
进程:进程是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的实例。每个进程都有自己的独立内存空间,一个进程至少有一个线程。
线程:线程是进程中的一个实体,是被系统独立调度和分派的基本单位。线程自身基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如执行栈),但它可以与同属一个进程的其他线程共享进程所拥有的全部资源。
-
资源拥有:
- 进程拥有独立的内存空间和系统资源,进程间的资源相互独立。
- 线程共享进程的内存空间和资源,一个线程的执行状态(如寄存器、堆栈等)对于同进程的其他线程是可见的。
-
独立性:
- 进程是独立运行的,一个进程崩溃不会直接影响到其他进程(除非它们有共享资源)。
- 线程是进程的一部分,一个线程的崩溃可能会导致整个进程的崩溃。
-
通信方式:
- 进程间通信(IPC)需要特定的机制,如管道、消息队列、共享内存或套接字等。
- 线程间可以直接读写进程的共享内存,通信更为方便。
-
执行:
- 每个进程有自己的程序计数器(PC),操作系统通过程序计数器来跟踪进程执行到何处。
- 线程共享进程的程序计数器,每个线程有自己的程序计数器。
#Java多线程及基础#
多线程的概念
-
线程的创建
-
线程的启动:
- 调用线程对象的
start()
方法启动线程。这会导致线程的run()
方法被执行。
- 调用线程对象的
-
线程的生命周期:
- 新建(New):线程对象被创建。
- 就绪(Runnable):线程可能正在运行,或者正在等待CPU时间片。
- 运行(Running):线程正在执行其
run()
方法。 - 阻塞(Blocked):线程等待某些条件(如I/O操作或获取同步锁)。
- 死亡(Terminated):线程执行完毕或被强制终止。
-
线程的调度:
- Java线程的调度由JVM和底层操作系统共同管理。Java提供了一些方法来控制线程的调度,如
yield()
和sleep()
。
- Java线程的调度由JVM和底层操作系统共同管理。Java提供了一些方法来控制线程的调度,如
-
线程的优先级:
- 线程具有优先级属性,可以通过
setPriority(int)
设置。高优先级的线程更可能获得CPU时间。
- 线程具有优先级属性,可以通过
-
线程的同步:
- 多线程环境下,多个线程可能会访问共享资源,需要同步机制来避免数据不一致。Java提供了
synchronized
关键字和其他同步工具(如ReentrantLock
)。
- 多线程环境下,多个线程可能会访问共享资源,需要同步机制来避免数据不一致。Java提供了
-
线程间通信:
- 线程可以通过共享变量、等待/通知机制(
wait()
、notify()
、notifyAll()
)等方式进行通信。
- 线程可以通过共享变量、等待/通知机制(
-
线程的中断:
- 线程可以通过
interrupt()
方法请求中断,被请求中断的线程应该检查中断状态,并在适当的时候响应中断。
- 线程可以通过
-
并发集合:
- Java提供了一些线程安全的集合类,如
ConcurrentHashMap
、CopyOnWriteArrayList
等,适用于多线程环境。
- Java提供了一些线程安全的集合类,如
-
线程池:
- 线程池用于管理线程的创建和销毁,提高资源利用率和执行效率。Java的
java.util.concurrent
包提供了多种线程池实现。
- 线程池用于管理线程的创建和销毁,提高资源利用率和执行效率。Java的
-
并发工具类:
- 如
CountDownLatch
、CyclicBarrier
、Semaphore
、Exchanger
等,这些工具类可以帮助开发者更容易地处理复杂的并发问题。
- 如
-
死锁:
- 死锁是多个线程相互等待对方持有的资源,导致程序停滞。Java提供了一些机制来预防和诊断死锁。
-
Java内存模型(JMM):
- 定义了线程如何通过内存进行通信,包括主内存和工作内存的概念,以及happens-before原则等。
线程的状态转换
-
新建(New):
- 这是线程对象被创建且尚未启动的状态。线程此时还没有分配给JVM。
-
可运行\就绪(Runnable):
- 线程被创建并调用了
start()
方法后,它进入可运行状态。此时线程具备了运行的条件,但可能正在等待JVM分配CPU时间片。
- 线程被创建并调用了
-
运行(Running):
- 可运行状态的线程一旦获得CPU时间片,就会进入运行状态开始执行
run()
方法。
- 可运行状态的线程一旦获得CPU时间片,就会进入运行状态开始执行
-
阻塞(Blocked):
- 当线程试图获取一个已被其他线程持有的锁时,它将进入阻塞状态。线程会等待直到锁被释放。
-
等待(Waiting):
- 线程因为调用了
Object.wait()
而在没有指定超时值的情况下进入等待状态。它需要其他线程调用相同对象的Object.notify()
或Object.notifyAll()
来唤醒。
- 线程因为调用了
-
超时等待(Timed Waiting):
- 当线程调用了带有超时参数的
Object.wait(long timeout)
、Thread.sleep(long millis)
、Thread.join(long millis)
等方法时,它将进入超时等待状态。线程会在指定的超时时间后自动唤醒。
- 当线程调用了带有超时参数的
-
终止(Terminated)-列子:
- 线程完成了它的
run()
方法,或者被其他线程通过Thread.stop()
方法(已过时,不推荐使用)强制终止后,进入终止状态。 -
public class ControlledThread implements Runnable { private volatile boolean running = true; @Override public void run() { while (running) { // 执行任务 } } public void stopRunning() { running = false; } }
- 线程完成了它的
#线程同步机制(synchronize、locks等)#
线程同步是多线程编程中的一个重要概念,用于控制对共享资源的并发访问,以防止数据不一致和竞争条件。以下是`synchronized`关键字的使用和锁的概念及作用的详细说明:
synchronized 关键字的使用
synchronized关键字在Java中用于实现同步锁,它可以确保同一时刻只有一个线程能够执行特定代码段。
- 同步实例方法
当在实例方法上使用`synchronized`关键字或在方法内部使用`synchronized`块时,锁住的是当前实例对象(this)。
public synchronized void myMethod() {
// 只有获得当前实例锁的线程可以执行此代码
}
- 同步静态方法
在静态方法上使用`synchronized`关键字时,锁住的是这个类的Class对象。
public static synchronized void myStaticMethod() {
// 只有获得该类Class对象锁的线程可以执行此代码
}
- 同步代码块
可以对任意对象加锁,通过在代码块前使用synchronized关键字和。
public void myMethod() {
Object lock = new Object();
synchronized (lock) {// 只有获得指定对象锁的线程可以执行此代码块
}
}
- 锁的释放
当执行完`synchronized`块内的代码后,锁会自动释放,允许其他线程进入同步块。
锁的概念和作用
- 锁的概念
锁是一种同步机制,用于控制对共享资源的访问。在多线程环境中,锁可以确保每次只有一个线程能够访问特定的代码段或资源。
- 内置锁 Monitor
Java的每个对象都有一个内置锁(也称为监视器锁),synchronized关键字就是利用这个内置锁来实现线程同步。
- 锁的作用
- 确保线程安全:防止多个线程同时修改共享数据,导致数据不一致。
- 保证执行顺序:通过锁可以控制线程的执行顺序,实现复杂的同步逻辑。
- 锁的公平性
- 锁可以是公平或非公平的。公平锁按照线程请求的顺序授予锁,非公平锁则允许线程抢占。
- 锁的其他实现
- 除了`synchronized`关键字,Java还提供了其他锁实现,如ReentrantLock、ReadWriteLock等,它们提供了更灵活的锁定操作。
- synchronized关键字的使用比较简单直观。
- 它在竞争激烈的情况下性能可能不如一些其他的锁实现,但在低竞争环境下表现良好。
- 锁的问题
- 可能导致死锁。
- 不支持响应中断,即不能在等待锁的过程中响应线程中断。