-
-
Save dnslin/fe657f9df08f4286c197c5e9e5fd6a51 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package in.dnsl; | |
import cn.hutool.log.Log; | |
import com.google.gson.Gson; | |
import com.google.gson.reflect.TypeToken; | |
import me.kuku.utils.Lists; | |
import me.kuku.utils.OkHttpUtils; | |
import okhttp3.Headers; | |
import okhttp3.Response; | |
import java.io.FileOutputStream; | |
import java.io.FileWriter; | |
import java.io.FileReader; | |
import java.io.IOException; | |
import java.net.InetSocketAddress; | |
import java.net.Proxy; | |
import java.util.List; | |
import java.util.Objects; | |
import java.util.concurrent.ExecutorService; | |
import java.util.concurrent.Executors; | |
import java.util.concurrent.TimeUnit; | |
public class Main { | |
static Log log = Log.get(); | |
static final Gson gson = new Gson(); | |
static List<Image> images = null; | |
static int maxThreads = 96; // 控制固定线程池的大小 | |
static ExecutorService virtualThreadPool = Executors.newFixedThreadPool(maxThreads, Thread.ofVirtual().factory()); | |
static String filePath = "/root/java_work/imglist/"; | |
// 失败list | |
static List<String> failList = Lists.newArrayList(); | |
public static void main(String[] args) { | |
OkHttpUtils.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890))); | |
List<String> types = List.of(".jpg", ".png"); | |
try { | |
images = gson.fromJson(new FileReader("output-2024-4-16.json"), new TypeToken<List<Image>>() { | |
}.getType()); | |
} catch (IOException e) { | |
log.info("读取文件失败: {}", e.getMessage()); | |
return; | |
} | |
log.info("加载到的图片数量: {}", images.size()); | |
images.forEach(image -> virtualThreadPool.submit(() -> { | |
for (String type : types) { | |
String url = convertPreviewToImageUrl(image.getHref(), type); | |
if (attemptToDownloadImage(url, 0)) { | |
image.setSourceUrl(url); // 更新Image对象 | |
break; | |
} | |
} | |
})); | |
virtualThreadPool.shutdown(); | |
try { | |
// 等待60秒看线程池是否完全关闭 | |
if (!virtualThreadPool.awaitTermination(2, TimeUnit.HOURS)) { | |
log.info("线程池在60秒内未完全关闭,尝试立即关闭所有正在执行的任务"); | |
virtualThreadPool.shutdownNow(); // 尝试取消正在执行的任务 | |
// 再等待60秒确认线程池是否关闭 | |
if (!virtualThreadPool.awaitTermination(2, TimeUnit.MINUTES)) { | |
log.info("线程池任务无法终止"); | |
} | |
} | |
} catch (InterruptedException ie) { | |
virtualThreadPool.shutdownNow(); // 响应中断,尝试立即关闭 | |
Thread.currentThread().interrupt(); // 保留中断状态 | |
} | |
// 将更新后的images列表写回到JSON文件 | |
writeImagesToJson(images, "output-2024-4-16-ok.json"); | |
writeImagesToJson(failList, "output-2024-4-16-fail.json"); | |
} | |
private static boolean attemptToDownloadImage(String url, int retryCount) { | |
if (retryCount >= 3) { | |
log.info("重试次数过多,放弃下载: {}", url); | |
failList.add(url); | |
return false; | |
} | |
try (Response response = OkHttpUtils.get(url, Headers.of("Connection", "close"))) { | |
switch (response.code()) { | |
case 200: | |
log.info("成功下载图片: {}", url); | |
byte[] bytes = Objects.requireNonNull(response.body()).bytes(); | |
writeImageToFile(bytes, url.substring(url.lastIndexOf('/') + 1)); | |
return true; | |
case 404: | |
log.info("图片不存在: {}", url); | |
return false; | |
case 429: | |
log.info("请求过于频繁,需要稍后重试: {}", url); | |
handleRateLimiting(); | |
return attemptToDownloadImage(url, retryCount + 1); | |
default: | |
log.info("其他HTTP响应: {}", response.code()); | |
return false; | |
} | |
} catch (Exception e) { | |
log.error("请求图片时出错: {}", e.fillInStackTrace()); | |
handleRateLimiting(); | |
return attemptToDownloadImage(url, retryCount + 1); | |
} | |
} | |
private static void handleRateLimiting() { | |
try { | |
log.info("等待5秒后重试"); | |
Thread.sleep(5000); // 延迟5秒后重试 | |
} catch (InterruptedException e) { | |
Thread.currentThread().interrupt(); | |
} | |
} | |
public static String convertPreviewToImageUrl(String previewUrl, String type) { | |
String id = previewUrl.substring(previewUrl.lastIndexOf('/') + 1); | |
return String.format("https://w.wallhaven.cc/full/%s/wallhaven-%s%s", id.substring(0, 2), id, type); | |
} | |
public static void writeImagesToJson(List<?> objects, String fileName) { | |
try (FileWriter writer = new FileWriter(fileName)) { | |
gson.toJson(objects, writer); | |
} catch (IOException e) { | |
log.error("写入文件时出错: {}", e.getMessage()); | |
} | |
} | |
public static void writeImageToFile(byte[] bytes, String fileName) { | |
try (FileOutputStream fos = new FileOutputStream(filePath + fileName)) { | |
fos.write(bytes); | |
log.info("成功写入文件: {}", fileName); | |
} catch (IOException e) { | |
log.error("写入文件时出错: {}", e.getMessage()); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
[arthas@293573]$ thread -n 3
"arthas-command-execute" Id=213 cpuUsage=0.43% deltaTime=0ms time=19ms RUNNABLE
at java.management@21.0.2/sun.management.ThreadImpl.dumpThreads0(Native Method)
at java.management@21.0.2/sun.management.ThreadImpl.getThreadInfo(ThreadImpl.java:482)
at com.taobao.arthas.core.command.monitor200.ThreadCommand.processTopBusyThreads(ThreadCommand.java:206)
at com.taobao.arthas.core.command.monitor200.ThreadCommand.process(ThreadCommand.java:122)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.process(AnnotatedCommandImpl.java:82)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.access$100(AnnotatedCommandImpl.java:18)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:111)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:108)
at com.taobao.arthas.core.shell.system.impl.ProcessImpl$CommandProcessTask.run(ProcessImpl.java:385)
at java.base@21.0.2/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
at java.base@21.0.2/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at java.base@21.0.2/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
at java.base@21.0.2/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base@21.0.2/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base@21.0.2/java.lang.Thread.runWith(Thread.java:1596)
at java.base@21.0.2/java.lang.Thread.run(Thread.java:1583)
"OkHttp w.wallhaven.cc" Id=198 cpuUsage=0.01% deltaTime=0ms time=79ms BLOCKED on okhttp3.internal.http2.Http2Stream@1a2677fc owned by "ForkJoinPool-1-worker-7" Id=115
at app//okhttp3.internal.http2.Http2Stream$FramingSource.receive$okhttp(Http2Stream.kt:425)
- blocked on okhttp3.internal.http2.Http2Stream@1a2677fc
at app//okhttp3.internal.http2.Http2Stream.receiveData(Http2Stream.kt:276)
at app//okhttp3.internal.http2.Http2Connection$ReaderRunnable.data(Http2Connection.kt:650)
at app//okhttp3.internal.http2.Http2Reader.readData(Http2Reader.kt:180)
at app//okhttp3.internal.http2.Http2Reader.nextFrame(Http2Reader.kt:119)
at app//okhttp3.internal.http2.Http2Connection$ReaderRunnable.invoke(Http2Connection.kt:618)
at app//okhttp3.internal.http2.Http2Connection$ReaderRunnable.invoke(Http2Connection.kt:609)
at app//okhttp3.internal.concurrent.TaskQueue$execute$1.runOnce(TaskQueue.kt:98)
at app//okhttp3.internal.concurrent.TaskRunner.runTask(TaskRunner.kt:116)
at app//okhttp3.internal.concurrent.TaskRunner.access$runTask(TaskRunner.kt:42)
at app//okhttp3.internal.concurrent.TaskRunner$runnable$1.run(TaskRunner.kt:65)
at java.base@21.0.2/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base@21.0.2/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base@21.0.2/java.lang.Thread.runWith(Thread.java:1596)
at java.base@21.0.2/java.lang.Thread.run(Thread.java:1583)
"OkHttp w.wallhaven.cc" Id=189 cpuUsage=0.01% deltaTime=0ms time=399ms BLOCKED on okhttp3.internal.http2.Http2Stream@4691d904 owned by "ForkJoinPool-1-worker-13" Id=121
at app//okhttp3.internal.http2.Http2Stream$FramingSource.receive$okhttp(Http2Stream.kt:425)
- blocked on okhttp3.internal.http2.Http2Stream@4691d904
at app//okhttp3.internal.http2.Http2Stream.receiveData(Http2Stream.kt:276)
at app//okhttp3.internal.http2.Http2Connection$ReaderRunnable.data(Http2Connection.kt:650)
at app//okhttp3.internal.http2.Http2Reader.readData(Http2Reader.kt:180)
at app//okhttp3.internal.http2.Http2Reader.nextFrame(Http2Reader.kt:119)
at app//okhttp3.internal.http2.Http2Connection$ReaderRunnable.invoke(Http2Connection.kt:618)
at app//okhttp3.internal.http2.Http2Connection$ReaderRunnable.invoke(Http2Connection.kt:609)
at app//okhttp3.internal.concurrent.TaskQueue$execute$1.runOnce(TaskQueue.kt:98)
at app//okhttp3.internal.concurrent.TaskRunner.runTask(TaskRunner.kt:116)
at app//okhttp3.internal.concurrent.TaskRunner.access$runTask(TaskRunner.kt:42)
at app//okhttp3.internal.concurrent.TaskRunner$runnable$1.run(TaskRunner.kt:65)
at java.base@21.0.2/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base@21.0.2/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base@21.0.2/java.lang.Thread.runWith(Thread.java:1596)
at java.base@21.0.2/java.lang.Thread.run(Thread.java:1583)