`
cuisuqiang
  • 浏览: 3937079 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
3feb66c0-2fb6-35ff-968a-5f5ec10ada43
Java研发技术指南
浏览量:3651493
社区版块
存档分类
最新评论

多线程访问 资源的安全控制

    博客分类:
  • JDK
阅读更多

对于线程安全,大家都知道使用synchronized控制访问的资源,有变量安全、方法安全、块安全。

我这里有个需求是这样的,我这里作为服务端有很多客户端与我进行交互,服务端也会主动发消息给客户端,但是要求每次交互时只能有一个用户。也就是说发送一组信息、等待信息、处理信息返回时这个链路只能有一个人使用

 

也许大家马上会想到这样写:

synchronized (ThreadT.devIpsIsCanUse) {
}

 

但是一旦这样写,在安全块内devIpsIsCanUse这个变量不能再被其他用户访问,因为此时这个资源是线程安全的,只能有一个线程进行访问。

如果此时我想访问不同线路,也是不行,因为一旦访问devIpsIsCanUse这个资源就会进行等待

可以这样写进行测试:

package com.hoo.mina;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ThreadT {
	public static Map<String, Boolean> devIpsIsCanUse = new ConcurrentHashMap<String, Boolean>();
	public static void main(String[] args) {
		devIpsIsCanUse.put("testKey1", true);
		devIpsIsCanUse.put("testKey2", true);
		new Thread(new ServiceImpl(1)).start();
		new Thread(new ServiceImpl(2)).start();

	}
}
class ServiceImpl implements Runnable {
	public int w;
	public ServiceImpl(int w) {
		this.w = w;
	}
	public void run() {
		while (true) {
			try {
				synchronized (ThreadT.devIpsIsCanUse) {
					if (ThreadT.devIpsIsCanUse.get("testKey" + w)){
						ThreadT.devIpsIsCanUse.put("testKey" + w, false);
						System.out.println(w + ":我来了:" + this.toString());
						Thread.sleep(2 * 1000);
						System.out.println(w + ":我走了:" + this.toString());
						ThreadT.devIpsIsCanUse.put("testKey" + w, true);
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

 

运行后发现,对于资源1和资源2的访问是排队的,这明显不符合要求

 

改动很简单,只要把处理的代码放到安全块外即可,因为对于是否使用的判断处理是非常快的,在用就继续循环否则向下走即可

package com.hoo.mina;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ThreadT {
	public static Map<String, Boolean> devIpsIsCanUse = new ConcurrentHashMap<String, Boolean>();
	public static void main(String[] args) {
		devIpsIsCanUse.put("testKey1", true);
		devIpsIsCanUse.put("testKey2", true);
		new Thread(new ServiceImpl(1)).start();
		new Thread(new ServiceImpl(2)).start();

	}
}
class ServiceImpl implements Runnable {
	public int w;
	public ServiceImpl(int w) {
		this.w = w;
	}
	public void run() {
		while (true) {
			try {
				synchronized (ThreadT.devIpsIsCanUse) {
					if (ThreadT.devIpsIsCanUse.get("testKey" + w)){
						ThreadT.devIpsIsCanUse.put("testKey" + w, false);
					}else{
						Thread.sleep(200);
						continue;
					}
				}
				System.out.println(w + ":我来了:" + this.toString());
				Thread.sleep(2 * 1000);
				System.out.println(w + ":我走了:" + this.toString());
				ThreadT.devIpsIsCanUse.put("testKey" + w, true);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

 

此时我们看到打印信息是资源1和资源2的访问是同时的,但是对于资源1的访问是需要排队的

 

那么此时我又在想,如果不加休眠,多个线程同时访问资源1时,如果A线程开始访问了且一直轮询,此时B再来访问,那么两个线程进安全块的顺序是必须A走完才能是B吗?

其实不是的在进安全块时,线程A和线程B是竞争的,而不是排队,可以这些看一下:

package com.hoo.mina;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ThreadT {
	public static Map<String, Boolean> devIpsIsCanUse = new ConcurrentHashMap<String, Boolean>();
	public static void main(String[] args) {
		devIpsIsCanUse.put("testKey1", true);
		new Thread(new ServiceImpl(1)).start();
		new Thread(new ServiceImpl(1)).start();
		new Thread(new ServiceImpl(1)).start();
		new Thread(new ServiceImpl(1)).start();
	}
}
class ServiceImpl implements Runnable {
	public int w;
	public ServiceImpl(int w) {
		this.w = w;
	}
	public void run() {
		while (true) {
			try {
				synchronized (ThreadT.devIpsIsCanUse) {
					if (ThreadT.devIpsIsCanUse.get("testKey" + w)){
						ThreadT.devIpsIsCanUse.put("testKey" + w, false);
					}else{
						Thread.sleep(500);
						System.out.println(w + ":被占中:" + this.toString());
						continue;
					}
				}
				System.out.println(w + ":我来了:" + this.toString());
				try {
					Thread.sleep(1 * 1000);
				} catch (Exception e) {
				}
				System.out.println(w + ":我走了:" + this.toString());
				ThreadT.devIpsIsCanUse.put("testKey" + w, true);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

 

看一下打印:

1:我来了:ServiceImpl@14318bb
1:被占中:ServiceImpl@1a758cb
1:被占中:ServiceImpl@1b67f74
1:我走了:ServiceImpl@14318bb
1:被占中:ServiceImpl@1b67f74
1:我来了:ServiceImpl@1b67f74

 

可以明显看到他们是竞争关系 

 

请您到ITEYE网站看原创,谢谢!

http://cuisuqiang.iteye.com/ ! 

自建博客地址:http://www.javacui.com/ ,内容与ITEYE同步!

1
0
分享到:
评论
3 楼 baohuan_love 2013-12-18  
文章写的很好
2 楼 cuisuqiang 2013-03-12  
以上虽然能实现我们的需要,但是仔细看就会发现问题,就是我在锁内休眠
这样就会造成其他线程访问时的等待,这也是一个严重的BUG

解决方法是,判断是否可用放到一个线程安全的方法中,由于方法是安全的,所以线程会依次进入不会出现问题,资源不能使用再休息,避免了不必要的锁

由于方法内只是做是否可用的判断,速度可以不计较,所以不必担心方法调用等待的问题
1 楼 jiangwenxian 2013-03-04  
学习了,多谢。

相关推荐

    Java线程安全问题_动力节点Java学院整理

    其实java的多线程并发问题最终都会反映在java的内存模型上,所谓线程安全无非是要控制多个线程对某个资源的有序访问或修改。总结java的内存模型,要解决两个主要的问题:可见性和有序性。我们都知道计算机有高速缓存...

    java多线程设计模式详解(PDF及源码)

    (注意,本资源附带书中源代码可供参考) 多线程与并发处理是程序设计好坏优劣的重要课题,本书通过浅显易懂的文字与实例来介绍Java线程相关的设计模式概念,并且通过实际的Java程序范例和 UML图示来一一解说,书中...

    C# 多线程对资源读写时如何控制的方法

    1、多个线程对同一个队列进行读写操作,要注意进行读写控制,某个线程在读取的时候,不允许其它线程读、写;某个线程在写的时候,不允许其它线程进行读写。 2、对字典进行读写时,进行独占式访问定义一个字典,再...

    JAVA线程安全及性能的优化

    其实JAVA的多线程并发问题最终都会反映在java的内存模型上,所谓线程安全无非是要控制多个线程对某个资源的有序访问或修改。总结java的内存模型,要解决两个主要的问题:可见性和有序性。我们都知道计算机有高速缓存...

    Java高级程序设计-多线程(二).pptx

    当多个线程访问同一个资源时,如果控制不好,也会造成数据的不正确性。 以银行取钱为例: 用户输入账户、密码,系统判断用户的账户、密码是否匹配 用户输入取款金额 系统判断账户余额是否大于取款金额 如果余额大于...

    linux之线程同步一.doc

    线程同步在多线程编程中非常重要,因为它可以确保各个线程之间的数据安全和正确性。 以下是Linux中常见的线程同步机制: 1. 互斥锁(Mutex):互斥锁是一种用于保护共享资源的同步机制。当一个线程获得了一个互斥...

    简单对比C#程序中的单线程与多线程设计

    而缺点在于线程需要占用内存,线程越多占用的内存就多,多线程需要协调和管理,所以需要占用CPU时间以便跟踪线程,线程之间对共享资源访问会互相影响,所以得解决争用共享资源的问题,线程太多,也会导致控制起来更...

    Delphi多线程编程之三 同步读写全局数据

    此参数设为nil,表示访问控制列表默认的安全属性。 bInitalOwner参数表示创建互斥对象的线程是否要成为此互斥对象的拥有者。当此参数为False时,表示互斥对象没有拥有者。 lpName参数指定互斥对象的名称。设为nil...

    米哈游笔试题目-Java方向.docx

    使用信号量实现资源访问控制:需要设计一个多线程程序,使用信号量实现对资源的多线程访问控制,能够限制同时访问资源的线程数量。 分布式锁类:需要设计一个分布式锁类,能够通过网络实现多个进程或多个服务器之间...

    Visual Basic.NET线程参考手册

    3.5 端到端的示例 3.5.1 编写自己的线程安全包装器 3.5.2 数据库连接池 3.6 本章小结第4章 设计模式 4.1 应用程序中的多线程 4.2 STA线程模式 4.3 MTA线程模式 4.3.1 指定线程模式 4.3.2 设计线程应用程序 4.3.3 ...

    c语言跨平台信号量封装

    信号量所为一种线程安全对象,在多线程开发中,是有一些使用场景的,比如多个线程或者进程共享同一个资源,或者生产者消费者模式的实现,都可以使用信号量来进行控制资源的有序访问。c语言做多线程开发,实现一个跨...

    Java各种锁的使用方式及其对比

    这些锁可以用来控制对共享资源的访问,从而保证数据一致性和线程安全。 在程序中使用锁需要注意锁定的粒度和时长,过大的锁粒度或过长的锁时间可能会导致性能问题。因此,在编写并发程序时,需要根据实际情况选择...

    linux之线程同步的概要介绍与分析

    在Linux操作系统中,线程同步是多线程编程中的一个核心概念,它确保了多个线程在访问共享资源时的正确性与一致性,避免了诸如数据竞争和竞态条件等问题。为了实现这一目标,Linux提供了一系列强大的线程同步机制和...

    单片机与DSP中的单片机系统中的多任务多线程机制的实现

    我们讨论的是,在不使用RTOS的控制系统中,如何体现多任务多线程机制的程序设计思想。 一些嵌入式设备可以需要操作系统,例如掌上电脑、PDA、网络控制器等高性能的手持设备和移动设备。它们往往和无线通信、互联网...

    基于并发访问请求关联的访问控制协调方法

    调研目前网络应用中并发访问请求的构成和相互联系,给出...针对网络应用,基于异步通讯方式和多线程技术提出通过访问请求调度实现访问控制协调的方法,保证系统的并发性和安全性,优化页面性能,为用户提供更好的使用体验。

    linux项目工程资料-基于Linux系统的应用程序,旨在搭建一套完整的多进程多线程通讯的消息框架.zip

    【此资源可私信博主有偿获取】 Linux项目是一个开放源代码...安全性:Linux操作系统在安全性方面表现出色,具有强大的访问控制和安全机制。这使得Linux成为了一种非常适合用于服务器和安全敏感的应用场景的操作系统。

    主要实现了远程监控局域网内的主机桌面与网络情况、简单键鼠控制、远程断网(ARP攻击)、数据加密传输等功能.zip

    远程控制主机 前言 本文为 HITwh 网络空间安全...主要功能包括:图形化界面,视频监控,鼠标键盘远程控制,记录监控时长,监控硬件资源使用,监控网络活动,中断网络访问等。为了更好的性能,还需要使用多线程模型。

    asp.net多线程的TCP端口扫描程序的设计与实现(源代码+thesis).zip

    安全性保护:我们将使用ASP.NET提供的身份验证和授权功能,确保只有经过授权的用户可以访问敏感数据和功能。我们还将使用加密技术来保护用户的敏感信息,如密码和支付信息。 缓存管理:为了提高应用程序的性能,我们...

    Java面试监理制作教程指导.rar

    Java是一种面向对象的高级编程语言,最初由Sun Microsystems...它提供了各种安全机制以防止恶意代码的攻击,例如通过字节码验证和安全管理器来控制对敏感资源的访问。 5. 多线程支持:Java内置的多线程支持使得编写并

    Java面试whitey

    Java是一种面向对象的高级编程语言,最初由Sun Microsystems...它提供了各种安全机制以防止恶意代码的攻击,例如通过字节码验证和安全管理器来控制对敏感资源的访问。 5. 多线程支持:Java内置的多线程支持使得编写并

Global site tag (gtag.js) - Google Analytics