NutzCN Logo
问答 Files.write 方法线程不安全吧
发布于 2446天前 作者 Rekoe 5701 次浏览 复制 上一个帖子 下一个帖子
标签:

调用了两次方法

Files.write(saveFile, Json.toJson(params, JsonFormat.compact()));

两个文件里的内容 一个文件的一部分在另外一个文件中了

34 回复

saveFile不一样, 但共用同一个 params 了???

@wendal 没有 params 都是new 的

	public void star2Json(String saveFile) {
		List<Constellation> readList = getList(Constellation.class);
		Map<Integer, List<NutMap>> params = new HashMap<>();
		for (Constellation constellation : readList) {
			int id = constellation.getStar();
			List<NutMap> list = params.get(id);
			if (list == null) {
				list = new ArrayList<>();
				params.put(id, list);
			}
			NutMap param = NutMap.NEW();
			param.putAll(Lang.obj2map(constellation));
			// ignore params
			param.remove("id");
			param.remove("star");
			param.remove("day");

			String loveInfo = param.getString("loveInfo");
			param.put("loveInfo", Lang.array2list(StringUtils.split(loveInfo, "|")));

			String moneyInfo = param.getString("moneyInfo");
			param.put("moneyInfo", Lang.array2list(StringUtils.split(moneyInfo, "|")));

			String helthInfo = param.getString("helthInfo");
			param.put("helthInfo", Lang.array2list(StringUtils.split(helthInfo, "|")));

			String moodInfo = param.getString("moodInfo");
			param.put("moodInfo", Lang.array2list(StringUtils.split(moodInfo, "|")));
			list.add(param);
		}
		Files.write(saveFile, Json.toJson(params, JsonFormat.compact()));
	public void word2Json(String saveFile) {
		List<Translate> readList = getList(Translate.class);
		Map<String, Translate> params = new HashMap<>();
		for (Translate translate : readList) {
			params.put(translate.getId(), translate);
		}
		Files.write(saveFile, Json.toJson(params, JsonFormat.compact()));
	}

这star2Json写成这样,不就只能保持最后一个Constellation 的值了?

这东西跟线程安全无关, Files.write就没有实例变量.

@wendal 我加了一个方法锁

我贴整个代码

public class Utils {

	private Map<String, Class<?>> eClassMap = new HashMap<>();

	private Map<String, List<?>> eDates = new HashMap<>();

	public Utils() {
		loadClass(Constellation.class);
		loadClass(Translate.class);
	}

	public <T> Class<T> getClazz(String sheetName) {
		@SuppressWarnings("unchecked")
		Class<T> clazz = (Class<T>) eClassMap.get(sheetName);
		return clazz;
	}

	private <T> void loadClass(Class<T> clazz) {
		J4EName j4EName = clazz.getAnnotation(J4EName.class);
		if (!Lang.isEmpty(j4EName)) {
			String name = j4EName.value();
			eClassMap.put(name, clazz);
		}
	}

	@SuppressWarnings("unchecked")
	public <T> List<T> getList(Class<T> clazz) {
		J4EName j4EName = clazz.getAnnotation(J4EName.class);
		if (!Lang.isEmpty(j4EName)) {
			String name = j4EName.value();
			return (List<T>) eDates.get(name);
		}
		return null;
	}

	public void loadXls(InputStream in) {
		eDates.clear();
		Iterator<Sheet> iterator = J4E.loadExcel(in).iterator();
		while (iterator.hasNext()) {
			Sheet sheet = iterator.next();
			String name = sheet.getSheetName();
			Class<?> clazz = getClazz(name);
			if (Lang.isEmpty(clazz)) {
				continue;
			}
			eDates.put(name, J4E.fromSheet(sheet, clazz, J4EConf.from(clazz), false));
		}
		Streams.safeClose(in);
	}

	public void star2Json(String saveFile) {
		List<Constellation> readList = getList(Constellation.class);
		Map<Integer, List<NutMap>> params = new HashMap<>();
		for (Constellation constellation : readList) {
			int id = constellation.getStar();
			List<NutMap> list = params.get(id);
			if (list == null) {
				list = new ArrayList<>();
				params.put(id, list);
			}
			NutMap param = NutMap.NEW();
			param.putAll(Lang.obj2map(constellation));
			// ignore params
			param.remove("id");
			param.remove("star");
			param.remove("day");

			String loveInfo = param.getString("loveInfo");
			param.put("loveInfo", Lang.array2list(StringUtils.split(loveInfo, "|")));

			String moneyInfo = param.getString("moneyInfo");
			param.put("moneyInfo", Lang.array2list(StringUtils.split(moneyInfo, "|")));

			String helthInfo = param.getString("helthInfo");
			param.put("helthInfo", Lang.array2list(StringUtils.split(helthInfo, "|")));

			String moodInfo = param.getString("moodInfo");
			param.put("moodInfo", Lang.array2list(StringUtils.split(moodInfo, "|")));
			list.add(param);
		}
		// Files.write(saveFile, Json.toJson(params, JsonFormat.compact()));
		write(saveFile, params);
	}

	private Object lock = new Object();

	public void write(String saveFile, Object params) {
		synchronized (lock) {
			Files.write(saveFile, Json.toJson(params, JsonFormat.compact()));
		}
	}

	public void word2Json(String saveFile) {
		List<Translate> readList = getList(Translate.class);
		Map<String, Translate> params = new HashMap<>();
		for (Translate translate : readList) {
			params.put(translate.getId(), translate);
		}
		write(saveFile, params);
	}
}

兽 是哪里的问题?

反正不是Files.write的问题

我加了锁 依然还是这个情况

继续把代码缩小

@wendal 单独执行两个中的任何一个数据都是完整的

那就是其他对象有重复了

这一步的问题吧, 提前打印一下内容看看

Json.toJson(params, JsonFormat.compact())

这个打印的没问题 应该是Files.write的事情了
@wendal

public File down() throws Exception {
		InputStream in = Streams.fileIn(Files.findFile(constellationPath));
		utils.loadXls(in);
		long time = System.currentTimeMillis();
		Files.createDirIfNoExists(new File(constellationTemp + "/" + time + "/json"));
		String starPath = constellationTemp + "/" + time + "/json/star.json";
		String wordPath = constellationTemp + "/" + time + "/json/word.json";
		utils.star2Json(starPath);
		utils.word2Json(wordPath);
		String zipPath = constellationTemp + "/" + time + "/json.zip";
		zip(zipPath, new File(constellationTemp + "/" + time + "/json"));
		return new File(zipPath);
	}

	private void zip(String zipFileName, File inputFile) throws Exception {
		ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFileName));
		BufferedOutputStream bo = new BufferedOutputStream(out);
		zip(out, inputFile, inputFile.getName(), bo);
		bo.close();
		out.close(); // 输出流关闭
	}

	private void zip(ZipOutputStream out, File f, String base, BufferedOutputStream bo) throws Exception { // 方法重载
		if (f.isDirectory()) {
			File[] fl = f.listFiles();
			if (fl.length == 0) {
				out.putNextEntry(new ZipEntry(base + "/")); // 创建zip压缩进入点base
				System.out.println(base + "/");
			}
			for (int i = 0; i < fl.length; i++) {
				zip(out, fl[i], base + "/" + fl[i].getName(), bo); // 递归遍历子文件夹
			}
		} else {
			out.putNextEntry(new ZipEntry(base)); // 创建zip压缩进入点base
			System.out.println(base);
			FileInputStream in = new FileInputStream(f);
			BufferedInputStream bi = new BufferedInputStream(in);
			int b;
			while ((b = bi.read()) != -1) {
				bo.write(b); // 将字节流写入当前zip目录
			}
			bi.close();
			in.close(); // 输入流关闭
		}
	}

时间戳做路径... 一并发就死啦...

就是为了 每次都换一个路径

确保每个线程的每次写入都是唯一,不重复的路径

不是这的问题
改成这个问题依旧

话说,你这是一次请求就发现数据不读呢?还是怎样测试的?

就点确定 下载 就一次请求

改为 R.UU32()

那跟线程安全没关系了,因为就一个线程

对 我改个写文件的方法 看看 现在定位到这个地方,json 数据现在是没问题的

	public void write(String saveFile, Object params) {
		String str = Json.toJson(params, JsonFormat.compact());
                log.debugf("path=%s data=%s", saveFile, str);
	        Files.write(saveFile, str);
                log.debugf("expect %s but %s", Lang.md5(new File(saveFile)), Lang.md5(str));
	}

好奇怪
我给你日志文件吧 兽
日志太大 传不上来

MD 好像是那个打zip的方法的问题的问题

@Rekoe 嗯,不使用函数生命周期外变量的函数,是没有线程安全方面问题滴 ~~~

添加回复
请先登陆
回到顶部