现有A、B两个线程,文件夹S中有10张图片,图片名分别为a1.jpg或a1.png、b2.jpg或b2.png、c3..d4..以此类推..k10.jpg或k10.png,A线程任务是往文件夹D中拷贝图片,B线程任务是每有一张图片拷贝进来,需将图片名称改成1.jpg或1.png。。以此类推到10.png或10.jpg,然后程序退出。要求:A线程不能一次拷贝多张图片,B线程不能一次修改多张图片名,即模拟生产者、消费者,拷贝进一个,修改一个名称
这道题目可以使用生产者-消费者模型来实现,其中 A 线程作为生产者,负责向文件夹 D 中拷贝图片;B 线程作为消费者,负责修改拷贝进来的图片名称。
具体实现思路如下:
定义一个共享的队列,用于存储拷贝进来的图片文件名。
A 线程循环遍历文件夹 S 中的图片,每次只拷贝一张图片到文件夹 D 中,并将拷贝的图片文件名加入队列中。
B 线程循环从队列中取出一个图片文件名,将其修改为指定格式,然后保存到文件夹 D 中。
当队列为空时,B 线程结束循环,程序退出。
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class Main {
public static void main(String[] args) {
// 定义文件夹 S 和 D 的路径
String srcDir = "/path/to/S";
String dstDir = "/path/to/D";
// 定义共享队列,用于存储拷贝进来的图片文件名
BlockingQueue<String> imageQueue = new LinkedBlockingQueue<>();
// 定义 A 线程,负责向 D 文件夹中拷贝图片
Thread threadA = new Thread(() -> {
// 遍历 S 文件夹中的图片
for (int i = 1; i <= 10; i++) {
String srcFile = srcDir + "/a" + i + ".jpg";
if (!new File(srcFile).exists()) {
srcFile = srcDir + "/a" + i + ".png";
}
String dstFile = dstDir + "/a" + i + ".jpg";
if (!new File(dstFile).exists()) {
dstFile = dstDir + "/a"".png";
}
try {
Files.copy(new File(srcFile).toPath(), new File(dstFile).toPath(), StandardCopyOption.REPLACE_EXISTING);
// 将拷贝的图片文件名加入队列中
imageQueue.put(new File(dstFile).getName());
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
});
// 定义 B 线程,负责修改拷贝进来的图片名称
Thread threadB = new Thread(() -> {
// 定义计数器,用于计数已经修改的图片数量
int count = 0;
while (count < 10) {
try {
// 从队列中取出一个图片文件名
String imageName = imageQueue.take();
// 修改图片文件名
String newImageName = String.format("%d%s", count + 1, imageName.substring(imageName.lastIndexOf('.')));
Path oldPath = new File(dstDir, imageName).toPath();
Path newPath = new File(dstDir, newImageName).toPath();
Files.move(oldPath, newPath, StandardCopyOption.REPLACE_EXISTING);
count++;
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
});
线程A的逻辑是从S文件夹拷贝图片文件到D文件夹,线程B的逻辑是从D文件夹拿出一个图片文件修改文件名。
可以把D文件夹看成是多线程操作中的临界区资源,是需要锁住的资源,伪代码比如: synchronized File file = new File("c:/d");
并且提供一个方法让A线程和B线程在操作时,能且只能通过我指定的这个方法来获取D文件夹对象来操作,
A线程要向文件夹写入新文件时,若能拿到对象则说明B线程未操作,否则只能先等待B线程先操作完后释放锁;B线程同理