什么是线程
线程就像是一条小路,允许程序在运行时同时做多件事。可以把它想象成一条跑道上跑步的跑者,而整个程序就是操场
线程的基本概念
线程是程序执行的基本单元。每个程序至少有一个线程(主线程),它负责执行程序中的代码
多线程:多个线程同时在运行,类似于操场上有多个跑步的跑者。这样可以让程序同时做更多的事情,例如同时下载文件和处理用户输入
为什么要用线程
提高效率:线程允许程序同时进行多项任务,例如:
下载文件的同时显示进度条
处理数据的同时响应用户点击
改善用户体验:如果一个应用程序只使用主线程(UI线程)来做所有的工作,比如下载数据或读取文件,用户界面可能会变得迟缓或无响应。使用线程可以避免这种情况,保持应用流畅
线程的工作原理
主线程(UI线程):这是程序启动时默认的线程,它处理用户界面和用户交互。主线程不能做耗时操作,比如网络请求,否则界面会变得卡顿
后台线程:用于执行耗时的操作,比如下载文件、处理大数据等。后台线程不会阻塞主线程,可以让主线程继续响应用户操作
线程的主要方法
thread.start():启动一个新线程。当调用 thread.start() 方法时,线程会从 run() 方法开始执行
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// 这是线程要做的工作
}
});
thread.start(); // 启动线程
run():定义线程要执行的代码。当线程启动时,run() 方法里的代码会被执行
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程在运行");
}
}).start();
thread.sleep(long millis):当前线程暂停执行指定的时间(毫秒)。thread.sleep() 方法使线程暂停执行
try {
Thread.sleep(2000); // 休眠2秒
} catch (InterruptedException e) {
e.printStackTrace();
}
参数解析:
millis:当前线程暂停执行指定的时间(毫秒)
thread.join():等待当前线程完成。调用 thread.join()可以等到另一个线程结束
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程正在执行任务");
}
});
thread.start();
try {
thread.join(); // 等待线程完成
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt():中断线程的休眠或等待状态。它会中断线程的等待或休眠状态,并引发 InterruptedException
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000); // 休眠5秒
} catch (InterruptedException e) {
System.out.println("线程被中断");
}
}
});
thread.start();
thread.interrupt(); // 中断线程
thread.isAlive():检查线程是否还在运行
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// 执行任务
}
});
thread.start();
System.out.println("线程是否还活着: " + thread.isAlive());
thread.setPriority(int priority):分配不同的任务优先级。优先级高的线程会优先获得CPU时间
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// 执行任务
}
});
thread.setPriority(Thread.MAX_PRIORITY); // 设置最高优先级
thread.start();
参数解析:
priority:设置线程的优先级。通常取值为:Thread.MIN_PRIORITY、Thread.NORM_PRIORITY、Thread.MAX_PRIORITY
主要方法总结
线程(Thread)是使程序可以同时执行多个任务的工具。主要方法包括:
start():启动线程,让它开始工作
run():定义线程要执行的代码
sleep(long millis):让线程暂停执行指定的时间
join():等待线程完成任务
interrupt():中断线程的休眠或等待状态
isAlive():检查线程是否还在运行
setPriority(int priority):设置线程的优先级
创建和使用线程
简单的线程
在后台做一个简单的任务,比如打印一条消息。可以创建一个线程来完成这个任务,而不会影响到主线程
// 创建一个新的线程
new Thread(new Runnable() {
// 定义了线程中要执行的任务
@Override
public void run() {
// 这是在后台线程中运行的代码
System.out.println("后台任务执行中...");
}
// 启动线程,线程开始执行run()方法中的代码
}).start();
线程池
如果有很多任务需要处理,创建和管理大量线程会很麻烦。线程池是一个很好的解决方案,它可以重用线程,管理线程的创建和销毁
// 创建一个线程池,最多同时运行4个线程
ExecutorService executor = Executors.newFixedThreadPool(4);
// 将任务提交给线程池执行
executor.submit(new Runnable() {
@Override
public void run() {
// 执行后台任务
System.out.println("线程池中的任务执行中...");
}
});
//关闭线程池,不再接受新任务
executor.shutdown(); // 关闭线程池
线程与用户界面更新
只有主线程可以更新用户界面。如果后台线程需要更新UI,可以使用以下方法:
runOnUiThread():可以在主线程中执行代码
runOnUiThread(new Runnable() {
@Override
public void run() {
// 更新用户界面
myTextView.setText("更新了UI!");
}
});
Handler:用于在主线程和其他线程之间传递消息和任务
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
// 更新UI
myTextView.setText("更新了UI!");
}
});
常见问题
死锁:当两个或多个线程互相等待对方释放资源,导致所有线程都无法继续运行。避免死锁的方法包括避免嵌套锁定和确保锁的获取顺序一致
资源竞争:当多个线程同时访问共享资源而导致的冲突。使用同步机制(如 synchronized 关键字或 Lock 类)可以避免资源竞争
总结
线程允许程序同时进行多个任务,提高效率和用户体验
使用线程可以保持应用的流畅性,避免界面冻结
线程池是管理大量线程的有效工具
线程与UI更新需要特别注意,通常使用runOnUiThread()或 Handler 来确保UI更新在主线程中进行