线程与进程
(1)线程是“进程代码段”的一次顺序执行流程。一个进程由一个或多个线程组成,一个进程至少有一个线程。
(2)线程是CPU调度的最小单位,进程是操作系统分配资源的最小单位。线程的划分尺度小于进程,使得多线程程序的并发性高。
(3)线程是出于高并发的调度诉求从进程内部演进而来的。线程的出现既充分发挥了CPU的计算性能,又弥补了进程调度过于笨重的问题。
(4)进程之间是相互独立的,但进程内部的各个线程之间并不完全独立。各个线程之间共享进程的方法区内存、堆内存、系统资源
(5)切换速度不同:线程上下文切换比进程上下文切换要快得多。所以,有的时候,线程也称为轻量级进程。
创建多线程
Java中创建多线程有三种方法:
- Thread类
- Runnable接口
- Callable接口
先封装一个输出语句,因为输出语句实在是太长了
class PRT{
public static void prtln(Object obj){
System.out.println(obj);
}
public static void prt(Object obj){
System.out.print(obj);
}
}
1. 使用Thread类
步骤:
- 自定义线程继承
Thread
类 - 重写
run()
方法 - 创建线程对象,调用
start()
方法启动线程
class TestThread1 extends Thread{
@Override
public void run() {
// 线程内
for (int i = 0; i < 1000; i++) {
PRT.prtln("run "+i);
}
}
}
public class Main {
public static void main(String[] args) {
TestThread1 testThread1 = new TestThread1();
testThread1.start();
// 主线程
for (int i = 0; i < 1000; i++) {
PRT.prtln("main "+i);
}
}
}
运行一下,可见内容是穿插输出的
多线程下载图片 Thread
首先导入apache commons-io包(自行下载即可,或者用maven)
package cn.vwmwv.thread;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
// 多线程同步下载图片
public class TestThread2 extends Thread {
private String url;
private String name;
public TestThread2(String url,String name){
this.name = name;
this.url = url;
}
@Override
public void run() {
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url,name);
PRT.prtln("下载完成,文件名为:"+name);
}
public static void main(String[] args) {
TestThread2 t1 = new TestThread2("https://s4.ax1x.com/2021/12/27/TDBt74.jpg","1.jpg");
TestThread2 t2 = new TestThread2("https://s4.ax1x.com/2021/12/27/TDBt74.jpg","2.jpg");
TestThread2 t3 = new TestThread2("https://s4.ax1x.com/2021/12/27/TDBt74.jpg","3.jpg");
t1.start();
t2.start();
t3.start();
}
}
class WebDownloader{
public void downloader(String url,String name) {
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
}catch (IOException e){
e.printStackTrace();
PRT.prtln("IO异常,downloader方法异常");
}
}
}
下载完成,显示如下
2. 实现Runnable接口
步骤:
- 定义
MyRunnable
类实现Runnable
接口 - 实现
run()
方法,编写线程执行体 - 创建线程对象,调用
start()
方法启动线程
package cn.vwmwv.thread;
// Runnable
public class TestThread3 implements Runnable {
@Override
public void run() {
// 线程内
for (int i = 0; i < 1000; i++) {
PRT.prtln("run "+i);
}
}
public static void main(String[] args) {
TestThread3 testThread3 = new TestThread3();
new Thread(testThread3).start();
// 主线程
for (int i = 0; i < 1000; i++) {
PRT.prtln("main "+i);
}
}
}
可见,依旧是穿插输出的:
多线程下载图片 Runnable
// 多线程下载图片 Runnable
public class DownPic implements Runnable {
private String url;
private String name;
public DownPic(String url,String name){
this.name = name;
this.url = url;
}
@Override
public void run() {
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url,name);
PRT.prtln("下载完成,文件名为:"+name);
}
public static void main(String[] args) {
DownPic t1 = new DownPic("https://s4.ax1x.com/2021/12/27/TDBt74.jpg","1.jpg");
DownPic t2 = new DownPic("https://s4.ax1x.com/2021/12/27/TDBt74.jpg","2.jpg");
DownPic t3 = new DownPic("https://s4.ax1x.com/2021/12/27/TDBt74.jpg","3.jpg");
new Thread(t1).start();
new Thread(t2).start();
new Thread(t3).start();
}
}
class WebDownloader{
public void downloader(String url,String name) {
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
}catch (IOException e){
e.printStackTrace();
PRT.prtln("IO异常,downloader方法异常");
}
}
}
3. 实现Callable接口
步骤:
- 实现Callble接口,需要返回值类型
- 重写call方法,需返回异常
- 创建目标对象
- 创建执行服务
- 提交执行
- 获取结果
- 关闭服务
多线程下载图片 Callable
package cn.vwmwv.thread;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;
public class TestCallable implements Callable<Boolean> {
private String url;
private String name;
public TestCallable(String url,String name) {
this.name = name;
this.url = url;
}
@Override
public Boolean call() throws Exception {
CallWebDownloader webDownloader = new CallWebDownloader();
webDownloader.downloader(url,name);
PRT.prtln("下载完成,文件名为:"+name);
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
String url = "https://cdn-ali-img-shstaticbz.shanhutech.cn/bizhi/staticwp/202106/87ad8b2009c489546b5d0a9482b5f08a--164538143.jpg";
// String name = "1.jpg";
TestCallable t1 = new TestCallable(url,"1.jpg");
TestCallable t2 = new TestCallable(url,"2.jpg");
TestCallable t3 = new TestCallable(url,"3.jpg");
// 创建执行服务
ExecutorService service = Executors.newFixedThreadPool(3);
// 提交 执行
Future<Boolean> r1 = service.submit(t1);
Future<Boolean> r2 = service.submit(t2);
Future<Boolean> r3 = service.submit(t3);
// 获取结果
Boolean rs1 = r1.get();
Boolean rs2 = r2.get();
Boolean rs3 = r3.get();
// 打印结果
PRT.prtln(rs1);
PRT.prtln(rs2);
PRT.prtln(rs3);
// 关闭服务
service.shutdown();
}
}
class CallWebDownloader{
public void downloader(String url,String name) {
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
}catch (IOException e){
e.printStackTrace();
PRT.prtln("IO异常,downloader方法异常");
}
}
}
参考资料
- 《Java高并发核心编程(卷2):多线程、锁、JMM、JUC、高并发设计模式》尼恩编著
- https://www.bilibili.com/video/BV1V4411p7EF