java多线程问题请教

落丶枫 2019-09-27 03:11:04
对于同一个工具类中的两个static方法f1()和f2(),如何能让它们实现互斥?需求是对于同一个用户来说f1()和f2()互斥,但是不同用户访问方法时不能互斥,比如多个用户同时访问f1()(或者f2())要能够并发访问。
目前在两个方法上都加了sychonized,这样虽然能实现同一用户的方法互斥,但是没法多用户并发访问,请问下这个怎么解决?
...全文
173 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
落丶枫 2019-09-27
  • 打赏
  • 举报
回复
引用 12 楼 瘦死的黑骆驼 的回复:
[quote=引用 10 楼 zifu9169 的回复:] [quote=引用 7 楼 瘦死的黑骆驼 的回复:] [quote=引用 6 楼 zifu9169 的回复:] [quote=引用 2 楼 瘦死的黑骆驼 的回复:] 你的同一个用户会同时有多线程在分别调用这两个方法吗,还是说只有一个线程,如果只有一个线程的话,那你就不需要加锁了,本来就是先调用一个方法再调用另一个方法的,难道你写代码不是逐行写的吗,比如 f1(); f2(); 虽然java有指令重排,但是对你这块的方法执行是不影响的,你加了synchronized也是白搭,加锁是伪了解决共享资源问题啊
应用场景还是针对文件上传时文件分片合并方法merge()以及本地上传文件删除方法delete()。merge()需要用到文件流,执行时间0.5-1s,如果merge()执行期间用户执行了delete(),由于文件流的关系会导致delete()执行失败无法删除文件,同时文件合并也会失败导致合成文件不完整。merge()和delete()是写在两个不同的controller里面的,会并发执行,因此需要sychonized使它们互不干扰。但是加上sychonized多个用户就不能同时访问merge()或delete()[/quote] 又是你 上次不是说判断当前文件是否已合并完成在考虑删除吗,我觉得那种方式挺好的啊,没有合并完成的话,删除就提示不能删除呗 或者你这两个方法里面是否可以获取到当前的用户对象user,然后方法里面对user加锁 synchronized(user){ // do something }[/quote] 哦,明白了,你的意思是这样写吧? merge():

public static  boolean mergeFiles(String folder, String filename, int chunkNum, IUser user){
    	synchronized(user) {
    		String targetFile = folder + "/" + filename;
            RandomAccessFile raf = null;
            try {
            	//申明随机读取文件RandomAccessFile
                raf = new RandomAccessFile(new File(targetFile), "rw");
                //开始合并文件,对应切片的二进制文件
                for (int i = 1; i <= chunkNum; i++) {
                	File chunkFile = new File(targetFile + "-" + i);
                    //读取切片文件
                	RandomAccessFile reader = new RandomAccessFile(chunkFile, "r");
                    byte[] b = new byte[10 * 1024 * 1024];
                    int n = 0;
                    try {
                       //先读后写	
                	   while ((n = reader.read(b)) != -1) {//读
                           raf.write(b, 0, n);//写
                       }
                    } catch(IOException e) {
                    	e.printStackTrace();
                    	return false;
                    } finally {
                    	try {
                    		//关闭流
            	            reader.close();
            	            //合并后删除分片文件
                            chunkFile.delete();
                    	} catch (IOException e) {
                    		e.printStackTrace();
                    		return false;
                    	}
                    }
                }
            } catch (FileNotFoundException e) {
            	e.printStackTrace();
            	return false;
            } finally {
                try {
                    raf.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    return false;
                }
            }
            return true;
    	}
    }
delete():

public static boolean deletefile(String delpath,IUser user){
		synchronized(user) {
			try {     
	        	System.gc();
	            File file = new File(delpath);
	            if(file.exists()) {
	            	// 当且仅当此抽象路径名表示的文件存在且 是一个目录时,返回 true
	                if (!file.isDirectory()) {
	                    file.delete();
	                } else if (file.isDirectory()) {
	                    String[] filelist = file.list();
	                    for (int i = 0; i < filelist.length; i++) {
	                        File delfile = new File(delpath + "\\" + filelist[i]);
	                        if (!delfile.isDirectory()) {
	                            delfile.delete();
	                            System.out.println(delfile.getAbsolutePath() + "删除文件成功");
	                        } else if (delfile.isDirectory()) {
	                            deletefile(delpath + "\\" + filelist[i]);
	                        }
	                    }
	                    System.out.println(file.getAbsolutePath() + "删除成功");
	                    file.delete();
	                }
	            } else {
	            	System.out.println("文件不存在");
	            }

	        } catch (Exception e) {
	            System.out.println("deletefile() Exception:" + e.getMessage());
	            return false;
	        }
	        return true;
	    }
	}
[/quote] 是滴[/quote] 明白了,感谢上面回复的各位大神啦
瘦死的黑骆驼 2019-09-27
  • 打赏
  • 举报
回复
引用 10 楼 zifu9169 的回复:
[quote=引用 7 楼 瘦死的黑骆驼 的回复:] [quote=引用 6 楼 zifu9169 的回复:] [quote=引用 2 楼 瘦死的黑骆驼 的回复:] 你的同一个用户会同时有多线程在分别调用这两个方法吗,还是说只有一个线程,如果只有一个线程的话,那你就不需要加锁了,本来就是先调用一个方法再调用另一个方法的,难道你写代码不是逐行写的吗,比如 f1(); f2(); 虽然java有指令重排,但是对你这块的方法执行是不影响的,你加了synchronized也是白搭,加锁是伪了解决共享资源问题啊
应用场景还是针对文件上传时文件分片合并方法merge()以及本地上传文件删除方法delete()。merge()需要用到文件流,执行时间0.5-1s,如果merge()执行期间用户执行了delete(),由于文件流的关系会导致delete()执行失败无法删除文件,同时文件合并也会失败导致合成文件不完整。merge()和delete()是写在两个不同的controller里面的,会并发执行,因此需要sychonized使它们互不干扰。但是加上sychonized多个用户就不能同时访问merge()或delete()[/quote] 又是你 上次不是说判断当前文件是否已合并完成在考虑删除吗,我觉得那种方式挺好的啊,没有合并完成的话,删除就提示不能删除呗 或者你这两个方法里面是否可以获取到当前的用户对象user,然后方法里面对user加锁 synchronized(user){ // do something }[/quote] 哦,明白了,你的意思是这样写吧? merge():

public static  boolean mergeFiles(String folder, String filename, int chunkNum, IUser user){
    	synchronized(user) {
    		String targetFile = folder + "/" + filename;
            RandomAccessFile raf = null;
            try {
            	//申明随机读取文件RandomAccessFile
                raf = new RandomAccessFile(new File(targetFile), "rw");
                //开始合并文件,对应切片的二进制文件
                for (int i = 1; i <= chunkNum; i++) {
                	File chunkFile = new File(targetFile + "-" + i);
                    //读取切片文件
                	RandomAccessFile reader = new RandomAccessFile(chunkFile, "r");
                    byte[] b = new byte[10 * 1024 * 1024];
                    int n = 0;
                    try {
                       //先读后写	
                	   while ((n = reader.read(b)) != -1) {//读
                           raf.write(b, 0, n);//写
                       }
                    } catch(IOException e) {
                    	e.printStackTrace();
                    	return false;
                    } finally {
                    	try {
                    		//关闭流
            	            reader.close();
            	            //合并后删除分片文件
                            chunkFile.delete();
                    	} catch (IOException e) {
                    		e.printStackTrace();
                    		return false;
                    	}
                    }
                }
            } catch (FileNotFoundException e) {
            	e.printStackTrace();
            	return false;
            } finally {
                try {
                    raf.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    return false;
                }
            }
            return true;
    	}
    }
delete():

public static boolean deletefile(String delpath,IUser user){
		synchronized(user) {
			try {     
	        	System.gc();
	            File file = new File(delpath);
	            if(file.exists()) {
	            	// 当且仅当此抽象路径名表示的文件存在且 是一个目录时,返回 true
	                if (!file.isDirectory()) {
	                    file.delete();
	                } else if (file.isDirectory()) {
	                    String[] filelist = file.list();
	                    for (int i = 0; i < filelist.length; i++) {
	                        File delfile = new File(delpath + "\\" + filelist[i]);
	                        if (!delfile.isDirectory()) {
	                            delfile.delete();
	                            System.out.println(delfile.getAbsolutePath() + "删除文件成功");
	                        } else if (delfile.isDirectory()) {
	                            deletefile(delpath + "\\" + filelist[i]);
	                        }
	                    }
	                    System.out.println(file.getAbsolutePath() + "删除成功");
	                    file.delete();
	                }
	            } else {
	            	System.out.println("文件不存在");
	            }

	        } catch (Exception e) {
	            System.out.println("deletefile() Exception:" + e.getMessage());
	            return false;
	        }
	        return true;
	    }
	}
[/quote] 是滴
oh_Maxy 2019-09-27
  • 打赏
  • 举报
回复
引用 4 楼 zifu9169 的回复:
[quote=引用 1 楼 oh_Maxy 的回复:]
f()可否加入参?比如用户id之类的,来区分。然后锁放到map<id, lock>,不同id用不同的锁。

f()可以传参,但是参数里怎么能够根据不同用户来加锁还是不太明白[/quote]
可以将登陆信息放到session,需要的时候,就把用户名之类的,一直透传给业务类。
落丶枫 2019-09-27
  • 打赏
  • 举报
回复
引用 7 楼 瘦死的黑骆驼 的回复:
[quote=引用 6 楼 zifu9169 的回复:] [quote=引用 2 楼 瘦死的黑骆驼 的回复:] 你的同一个用户会同时有多线程在分别调用这两个方法吗,还是说只有一个线程,如果只有一个线程的话,那你就不需要加锁了,本来就是先调用一个方法再调用另一个方法的,难道你写代码不是逐行写的吗,比如 f1(); f2(); 虽然java有指令重排,但是对你这块的方法执行是不影响的,你加了synchronized也是白搭,加锁是伪了解决共享资源问题啊
应用场景还是针对文件上传时文件分片合并方法merge()以及本地上传文件删除方法delete()。merge()需要用到文件流,执行时间0.5-1s,如果merge()执行期间用户执行了delete(),由于文件流的关系会导致delete()执行失败无法删除文件,同时文件合并也会失败导致合成文件不完整。merge()和delete()是写在两个不同的controller里面的,会并发执行,因此需要sychonized使它们互不干扰。但是加上sychonized多个用户就不能同时访问merge()或delete()[/quote] 又是你 上次不是说判断当前文件是否已合并完成在考虑删除吗,我觉得那种方式挺好的啊,没有合并完成的话,删除就提示不能删除呗 或者你这两个方法里面是否可以获取到当前的用户对象user,然后方法里面对user加锁 synchronized(user){ // do something }[/quote] 哦,明白了,你的意思是这样写吧? merge():

public static  boolean mergeFiles(String folder, String filename, int chunkNum, IUser user){
    	synchronized(user) {
    		String targetFile = folder + "/" + filename;
            RandomAccessFile raf = null;
            try {
            	//申明随机读取文件RandomAccessFile
                raf = new RandomAccessFile(new File(targetFile), "rw");
                //开始合并文件,对应切片的二进制文件
                for (int i = 1; i <= chunkNum; i++) {
                	File chunkFile = new File(targetFile + "-" + i);
                    //读取切片文件
                	RandomAccessFile reader = new RandomAccessFile(chunkFile, "r");
                    byte[] b = new byte[10 * 1024 * 1024];
                    int n = 0;
                    try {
                       //先读后写	
                	   while ((n = reader.read(b)) != -1) {//读
                           raf.write(b, 0, n);//写
                       }
                    } catch(IOException e) {
                    	e.printStackTrace();
                    	return false;
                    } finally {
                    	try {
                    		//关闭流
            	            reader.close();
            	            //合并后删除分片文件
                            chunkFile.delete();
                    	} catch (IOException e) {
                    		e.printStackTrace();
                    		return false;
                    	}
                    }
                }
            } catch (FileNotFoundException e) {
            	e.printStackTrace();
            	return false;
            } finally {
                try {
                    raf.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    return false;
                }
            }
            return true;
    	}
    }
delete():

public static boolean deletefile(String delpath,IUser user){
		synchronized(user) {
			try {     
	        	System.gc();
	            File file = new File(delpath);
	            if(file.exists()) {
	            	// 当且仅当此抽象路径名表示的文件存在且 是一个目录时,返回 true
	                if (!file.isDirectory()) {
	                    file.delete();
	                } else if (file.isDirectory()) {
	                    String[] filelist = file.list();
	                    for (int i = 0; i < filelist.length; i++) {
	                        File delfile = new File(delpath + "\\" + filelist[i]);
	                        if (!delfile.isDirectory()) {
	                            delfile.delete();
	                            System.out.println(delfile.getAbsolutePath() + "删除文件成功");
	                        } else if (delfile.isDirectory()) {
	                            deletefile(delpath + "\\" + filelist[i]);
	                        }
	                    }
	                    System.out.println(file.getAbsolutePath() + "删除成功");
	                    file.delete();
	                }
	            } else {
	            	System.out.println("文件不存在");
	            }

	        } catch (Exception e) {
	            System.out.println("deletefile() Exception:" + e.getMessage());
	            return false;
	        }
	        return true;
	    }
	}
落丶枫 2019-09-27
  • 打赏
  • 举报
回复
引用 7 楼 瘦死的黑骆驼 的回复:
[quote=引用 6 楼 zifu9169 的回复:] [quote=引用 2 楼 瘦死的黑骆驼 的回复:] 你的同一个用户会同时有多线程在分别调用这两个方法吗,还是说只有一个线程,如果只有一个线程的话,那你就不需要加锁了,本来就是先调用一个方法再调用另一个方法的,难道你写代码不是逐行写的吗,比如 f1(); f2(); 虽然java有指令重排,但是对你这块的方法执行是不影响的,你加了synchronized也是白搭,加锁是伪了解决共享资源问题啊
应用场景还是针对文件上传时文件分片合并方法merge()以及本地上传文件删除方法delete()。merge()需要用到文件流,执行时间0.5-1s,如果merge()执行期间用户执行了delete(),由于文件流的关系会导致delete()执行失败无法删除文件,同时文件合并也会失败导致合成文件不完整。merge()和delete()是写在两个不同的controller里面的,会并发执行,因此需要sychonized使它们互不干扰。但是加上sychonized多个用户就不能同时访问merge()或delete()[/quote] 又是你 上次不是说判断当前文件是否已合并完成在考虑删除吗,我觉得那种方式挺好的啊,没有合并完成的话,删除就提示不能删除呗 或者你这两个方法里面是否可以获取到当前的用户对象user,然后方法里面对user加锁 synchronized(user){ // do something }[/quote] 问题是现在还有一个取消按钮,不可能在合并完成之前把取消按钮隐藏掉,我试试用户锁,这个不太懂,我是希望两个方法互斥,为啥要加用户锁,这样不就是不同用户之间互斥吗?对于多线程我是糊里糊涂
maradona1984 2019-09-27
  • 打赏
  • 举报
回复
synchronized对用户id加锁集客
瘦死的黑骆驼 2019-09-27
  • 打赏
  • 举报
回复
引用 6 楼 zifu9169 的回复:
[quote=引用 2 楼 瘦死的黑骆驼 的回复:] 你的同一个用户会同时有多线程在分别调用这两个方法吗,还是说只有一个线程,如果只有一个线程的话,那你就不需要加锁了,本来就是先调用一个方法再调用另一个方法的,难道你写代码不是逐行写的吗,比如 f1(); f2(); 虽然java有指令重排,但是对你这块的方法执行是不影响的,你加了synchronized也是白搭,加锁是伪了解决共享资源问题啊
应用场景还是针对文件上传时文件分片合并方法merge()以及本地上传文件删除方法delete()。merge()需要用到文件流,执行时间0.5-1s,如果merge()执行期间用户执行了delete(),由于文件流的关系会导致delete()执行失败无法删除文件,同时文件合并也会失败导致合成文件不完整。merge()和delete()是写在两个不同的controller里面的,会并发执行,因此需要sychonized使它们互不干扰。但是加上sychonized多个用户就不能同时访问merge()或delete()[/quote] 又是你 上次不是说判断当前文件是否已合并完成在考虑删除吗,我觉得那种方式挺好的啊,没有合并完成的话,删除就提示不能删除呗 或者你这两个方法里面是否可以获取到当前的用户对象user,然后方法里面对user加锁 synchronized(user){ // do something }
落丶枫 2019-09-27
  • 打赏
  • 举报
回复
引用 2 楼 瘦死的黑骆驼 的回复:
你的同一个用户会同时有多线程在分别调用这两个方法吗,还是说只有一个线程,如果只有一个线程的话,那你就不需要加锁了,本来就是先调用一个方法再调用另一个方法的,难道你写代码不是逐行写的吗,比如 f1(); f2(); 虽然java有指令重排,但是对你这块的方法执行是不影响的,你加了synchronized也是白搭,加锁是伪了解决共享资源问题啊
应用场景还是针对文件上传时文件分片合并方法merge()以及本地上传文件删除方法delete()。merge()需要用到文件流,执行时间0.5-1s,如果merge()执行期间用户执行了delete(),由于文件流的关系会导致delete()执行失败无法删除文件,同时文件合并也会失败导致合成文件不完整。merge()和delete()是写在两个不同的controller里面的,会并发执行,因此需要sychonized使它们互不干扰。但是加上sychonized多个用户就不能同时访问merge()或delete()
瘦死的黑骆驼 2019-09-27
  • 打赏
  • 举报
回复
你的同一个用户会同时有多线程在分别调用这两个方法吗,还是说只有一个线程,如果只有一个线程的话,那你就不需要加锁了,本来就是先调用一个方法再调用另一个方法的,难道你写代码不是逐行写的吗,比如 f1(); f2(); 虽然java有指令重排,但是对你这块的方法执行是不影响的,你加了synchronized也是白搭,加锁是伪了解决共享资源问题啊
落丶枫 2019-09-27
  • 打赏
  • 举报
回复
引用 1 楼 oh_Maxy 的回复:
f()可否加入参?比如用户id之类的,来区分。然后锁放到map<id, lock>,不同id用不同的锁。
f()可以传参,但是参数里怎么能够根据不同用户来加锁还是不太明白
落丶枫 2019-09-27
  • 打赏
  • 举报
回复
引用 2 楼 瘦死的黑骆驼 的回复:
不懂你这个互斥是什么意思,是同一个用户访问了f1就不能再调用f2?还是当前用户会有多个线程同时执行,同一时刻只能访问其中一个方法? 还有你这个本身就是设计缺陷,工具类里的方法怎么还会存在你所谓的互斥关系?
互斥就是f1被调用时f2需要等待f1执行完成后再执行,两个方法只能有一个方法持有锁,不能同时执行
瘦死的黑骆驼 2019-09-27
  • 打赏
  • 举报
回复
不懂你这个互斥是什么意思,是同一个用户访问了f1就不能再调用f2?还是当前用户会有多个线程同时执行,同一时刻只能访问其中一个方法? 还有你这个本身就是设计缺陷,工具类里的方法怎么还会存在你所谓的互斥关系?
oh_Maxy 2019-09-27
  • 打赏
  • 举报
回复
f()可否加入参?比如用户id之类的,来区分。然后锁放到map<id, lock>,不同id用不同的锁。

67,513

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧