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

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

    博客分类:
  • 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  
学习了,多谢。

相关推荐

    多线程同步(多线程如何访问临界区资源)

    然而,多线程环境下的资源共享往往伴随着数据竞争问题,这时就需要引入线程同步机制,以确保共享资源的安全访问。本文将深入探讨多线程同步中的“临界区”概念及其在实际应用中的示例。 临界区是一种线程同步原语,...

    多线程ADO安全访问SQL

    总结,多线程ADO安全访问SQL涉及到数据库并发控制、事务管理、线程同步和资源管理等多个方面。开发者必须理解这些概念并正确实施,以确保应用程序的稳定性和数据的准确性。通过合理的设计和编程实践,可以在提高性能...

    python 多线程实现多个网址的多次快速访问

    在Python编程中,多线程是一种并发执行任务的机制,尤其在处理I/O密集型任务如网络请求时,能够显著提高程序效率。...在编写这样的程序时,我们需要关注线程安全、资源管理以及并发控制,以确保程序的正确性和高效性。

    C#多线程互斥实例 多线程获取同一变量

    例如,`Mutex`允许跨进程的互斥访问,而`Semaphore`则可以控制同时访问资源的线程数量。 测试这个多线程互斥的例子,我们可以创建多个线程,每个线程分别调用`Increment`或`Decrement`方法,然后观察`GetValue`返回...

    多线程资源共享集合

    本文将深入探讨多线程环境下如何管理和控制资源共享,主要关注`synchronized`关键字、`Runnable`接口以及`Thread`类的使用。 首先,让我们了解什么是多线程。多线程是指在一个进程中同时执行多个线程,每个线程都有...

    Delphi多线程的安全问题分析及解决

    ### Delphi多线程的安全问题分析及解决 #### 摘要 本文深入探讨了Delphi环境下多线程运行过程中可能遇到的安全问题及其解决方案。在Windows操作系统中,多线程技术因其高效性和灵活性而被广泛应用于软件开发之中。...

    易语言完美多线程控制例子

    总的来说,“易语言完美多线程控制例子”是一个极好的学习资源,它让我们有机会实践易语言的多线程编程,掌握如何在实际项目中应用这些技术。无论是对于初学者还是经验丰富的开发者,理解并掌握多线程控制都是提升...

    多线程单例模式并发访问

    多线程安全问题主要出现在共享资源的访问上。当多个线程同时访问相同的资源(共享变量)时,如果没有正确的同步机制,可能会导致不可预测的结果。 - **原因**:存在共享数据,并且存在对共享数据的多条操作路径,...

    大漠多线程模板_大漠_大漠多线程_

    2. **线程同步**:在多线程环境中,防止数据竞争和确保资源安全访问是至关重要的。C#提供了多种同步机制,如`Mutex`、`Semaphore`、`Monitor`和`lock`关键字。模板可能内置了这些同步工具的使用,减少了因不当同步...

    操作多线程删除数据库表,以及控制listbox多线程呈现

    在这个"操作多线程删除数据库表,以及控制listbox多线程呈现"的小程序中,我们将探讨如何利用多线程来处理数据库操作和UI更新。 1. **多线程基础**:多线程是指在一个应用程序中同时运行多个独立的执行流。在.NET ...

    WinCe多线程访问winform中控件

    总之,WinCe上的多线程访问WinForm控件需要开发者深入理解线程同步、UI线程安全以及异步编程。遵循上述原则,可以有效防止异常,提高程序的稳定性和用户体验。在实际编程过程中,应始终牢记,UI控件的修改应由创建它...

    C#多线程读写sqlite

    3. **线程安全**:在多线程环境中,对SQLite的读写操作需要确保线程安全。否则,多个线程同时访问数据库可能导致数据损坏或不一致。C#中的`lock`关键字是一种同步机制,可以防止多个线程同时访问共享资源。 4. **...

    易语言多线程控制线程数量源码

    本篇将深入探讨易语言中如何实现多线程控制以及线程数量的管理。 在易语言中,线程用于在单个进程中同时执行多个独立的代码段,从而提高程序的执行效率。创建线程的基本步骤包括定义线程函数、创建线程对象和启动...

    NET中多线程间资源共享与访问

    为了确保线程安全,即在多线程环境中正确管理和访问资源,.NET提供了一系列工具和技术。其中,`lock`关键字、`Monitor`类和`Mutex`类是最常用的方法。 - **lock关键字**:这是一种简单的同步机制,用于保护对临界区...

    多线程安全dictionary

    - 在读多写少的情况下,`ReaderWriterLockSlim`能提高性能,因为多个读取者可以同时访问资源,只有写入者需要独占锁。 - 但是,使用这种同步机制需要谨慎,避免死锁和资源泄漏。 3. **Mutex 或 Semaphore** - 另...

    C# 多线程控制实例

    总结来说,C#的多线程控制实例涉及创建线程、启动和停止线程、线程间的同步和通信,以及如何安全地管理线程。通过理解和熟练运用这些概念,开发者可以编写出高效、稳定的多线程程序。在实践中,要特别注意避免常见的...

    多线程编程示例

    4. **线程安全**:如果一个方法或数据结构在多线程环境下能正确工作,我们就称其为线程安全。线程安全可以通过设计、同步机制或使用线程安全的数据结构来实现。 在实践中,多线程编程还需要关注性能和资源消耗,...

    05.多线程数据保护(安全队列2

    1. **线程安全**:安全队列保证了在多线程环境下的并发访问是安全的,它内部实现了锁或者其他同步机制,避免了线程间的不协调操作。 2. **阻塞操作**:安全队列的插入(offer、put)和删除(poll、take)操作如果在...

    多线程实现多控制两个案例

    在多线程环境中,当多个线程访问共享资源时,如果没有适当的同步机制,可能会导致数据不一致或竞态条件。Java提供了多种同步工具,如`synchronized`关键字、`wait()`, `notify()`, `notifyAll()`方法,以及`Lock`...

    易语言多线程操作

    - 线程安全:需要确保在多线程环境下,程序的正确性和一致性,避免出现未预期的结果。 5. **文件"多线程控制.e"**: 这个文件很可能是易语言的一个示例程序,演示了如何在易语言中实现多线程控制。通过打开并学习...

Global site tag (gtag.js) - Google Analytics