`
qifeifei
  • 浏览: 27660 次
  • 来自: 上海
社区版块
存档分类
最新评论

java 多线程高并发读写控制 误区

阅读更多

先看一下下面的错误代码,对写加了synchronized控制,保证了写的安全,但是问题在哪里呢?

public class testTh7 {
	private String data;
	public String read(){
		System.out.println(Thread.currentThread().getName() + "read data " + data);
		return this.data;
	}
	public  synchronized void write(String data){
		System.out.println(Thread.currentThread().getName() + " === write data " + data);
		this.data = data;
	}

	public static void main(String[] args) {
		final testTh7 t = new testTh7();
		for (int i = 0; i < 100; i++) {
			if (i % 2 == 0) {
				new Thread(new Runnable() {
					@Override
					public void run() {
						Double d = Math.random();
						t.write(d.toString());
					}
				}).start();
			} else {
				new Thread(new Runnable() {
					@Override
					public void run() {
						t.read();
					}
				}).start();
			}
		}
	}
}

 程序的前部分输出结果如下:

Thread-1read data null

Thread-0 === write data 0.8429852467390618

Thread-2 === write data 0.3111022600208211

Thread-3read data 0.3111022600208211

Thread-4 === write data 0.13391602356879362

Thread-5read data 0.13391602356879362

Thread-8 === write data 0.3014059888796128

Thread-6 === write data 0.7073336550466512

Thread-7read data 0.7073336550466512

Thread-9read data 0.7073336550466512

Thread-10 === write data 0.3157260014049781

Thread-11read data 0.3157260014049781

Thread-15read data 0.3157260014049781

Thread-14 === write data 0.9981422731405993

Thread-16 === write data 0.9011910270245219

Thread-12 === write data 0.34975057489898076

Thread-13read data 0.34975057489898076

Thread-17read data 0.34975057489898076

Thread-18 === write data 0.19089943846264656

Thread-19read data 0.19089943846264656

Thread-21read data 0.19089943846264656

Thread-20 === write data 0.38498810226852065

Thread-22 === write data 0.29234432278529343

Thread-23read data 0.29234432278529343

Thread-27read data 0.29234432278529343

Thread-24 === write data 0.28981062022967496

Thread-29read data 0.28981062022967496

Thread-28 === write data 0.1022791336198855

Thread-26 === write data 0.15466728987586276

Thread-25read data 0.15466728987586276

Thread-31read data 0.15466728987586276

Thread-32 === write data 0.13431233603464776

Thread-33read data 0.13431233603464776

Thread-35read data 0.13431233603464776

Thread-38 === write data 0.33289010029186195

Thread-37read data 0.13431233603464776

Thread-34 === write data 0.5545937895404677

Thread-30 === write data 0.9567137584265717

Thread-36 === write data 0.6461050880921616

 

可以看到Thread-37这行读取的数据已经不正确了,读取的上一次的旧数据,这不是线程安全的缓存设计。首先确认一下原则,只能有一个线程写操作,可以多个线程并发读,但是写时不能读,读时候不能写。

解决办法有多种,可以使用信号量,使用两个信号量,一个是读写的信号量,还有个是写的信号量,如果简单一点,也可以使用java已经封装的读写锁,代码如下,可以自己测试。

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class testReadWrite {

	private String data = null;
	private ReentrantReadWriteLock rw = new ReentrantReadWriteLock();

	public void read() {
		rw.readLock().lock();
		System.out.println(Thread.currentThread().getName() + " read data!");
		System.out.println(Thread.currentThread().getName() + "read data " + data);
		rw.readLock().unlock();
	}

	public void write(String data) {
		rw.writeLock().lock();
		System.out.println(Thread.currentThread().getName() + " ===write data!");
		this.data = data;
		System.out.println(Thread.currentThread().getName() + " ===write data: " + data);
		rw.writeLock().unlock();
	}

}

 

 

3
5
分享到:
评论
14 楼 qifeifei 2015-05-11  
这个代码很明显有读也有写,但是释放锁没有在finally里面写。
13 楼 focus2008 2015-05-11  
qifeifei 写道
11楼的理解是在读前面也加上synchronized吗?对并发读你怎么解决呢?

如果只有并发读,没有写的话。就不需要锁了,只要保证“被正确的发布”就行了。

如果有读也有写,那么你只在写上加锁,不在读上加锁,那么你就犯了基本的错误了。你看下effective java那本书中关于并发的条目吧。

另外显示锁,你的用法也是有问题的,一般像下面这样用:
rw.writeLock().lock();
try{   
    // ... ...
}finally{
    rw.writeLock().unlock();
}
确保锁一定被释放。
12 楼 qifeifei 2015-05-11  
11楼的理解是在读前面也加上synchronized吗?对并发读你怎么解决呢?
11 楼 LieutenantGeneral 2015-05-09  
1、不是这个并发有问题,是你的理解有问题:你想实现读写互斥,你只是在写方法加了一个synchronized,这样会使得你写的时候不会被其他线程抢占资源,会把你想写入的东西写入。要实现读写互斥,你至少需要对读写加都加一个synchronized,最好用该类的class还作为锁。

2、并发代码写之前还是最好搞清思路,至于说的性能问题,synchronized是一直在优化的,而且一般你工作的时候的代码我估计也不会考虑那么多、
10 楼 haochong 2015-05-09  
楼主的多线程还得多学习哈。。
9 楼 focus2008 2015-05-09  
qifeifei 写道
在多线程环境并存在大量竞争的情况下,synchronized的用时迅速上升,而lock却依然保存不变或增加很少。你可以测试1,50,100,1000,15000个线程同时跑的时间,很明显越到后面,synchronized的用时明显增加,而显示lock一直保持着。

建议你实际测试下,再说。这你的这个例子中,读写比例是1:1,读写锁肯定不比synchronized有优势
8 楼 focus2008 2015-05-09  
ReentrantReadWriteLock的实现是很复杂的,它的执行的代码路径是很长的,所以只有在读比写多很多时,才值得使用。
7 楼 focus2008 2015-05-09  
首先普通的显示锁肯定性能上不比synchronized有优势。另外至于读写锁,只有在读比写多很多的情况下,才比普通的synchronized有优势.普通的显示锁绝对不比synchronized有优势。因为synchronized是内置的,相对而言更好优化,更值得优化,也更有可能会进行优化。
6 楼 qifeifei 2015-05-08  
在多线程环境并存在大量竞争的情况下,synchronized的用时迅速上升,而lock却依然保存不变或增加很少。你可以测试1,50,100,1000,15000个线程同时跑的时间,很明显越到后面,synchronized的用时明显增加,而显示lock一直保持着。
5 楼 剑走天涯 2015-05-08  
qifeifei 写道
synchronized如果都加在读和写上面,会大大影响多线程的并发性。

谁说的,你的依据是什么?在jdk6以后synchronized优化了,不会比你有ReentrantReadWriteLock性能损失多少,在以后的jdk中,synchronized会更加优化,而Lock相关的没什么优化空间了
4 楼 qifeifei 2015-05-08  
synchronized如果都加在读和写上面,会大大影响多线程的并发性。
3 楼 focus2008 2015-05-08  
你没有理解java中synchronized的含义,他是同步的意思,包含两层含义:互斥性和可见性。read()方法为了保证读取到write()方法中赋值的最新的data,必须也同时加上synchronized。当然你用读写锁也可以保证read()方法对data的可见性
2 楼 qifeifei 2015-05-08  
volatile关键字不能保证操作原子性的,它能保证变量在不同线程下的可见性。
1 楼 lilin 2015-05-08  
volatile关键字不行吗?

相关推荐

    Java多线程与并发库高级应用

    并发库高级应用\多线程\Java

    java 多线程并发实例

    在并发控制中,我们通常会遇到以下几个关键概念: - 同步:确保同一时间只有一个线程访问共享资源,防止数据不一致。Java提供了synchronized关键字以及Lock接口(如ReentrantLock)来实现同步。 - volatile:修饰...

    java多线程与高并发视频

    java多线程与高并发java多线程与高并发java多线程与高并发

    Java多线程高并发篇(一)--重入锁

    在Java多线程高并发编程中,重入锁(ReentrantLock)是一个至关重要的概念,它提供了比Java内置锁(synchronized)更细粒度的控制,并且具有更高的可读性和可扩展性。本篇文章将深入探讨重入锁的相关知识点。 首先...

    java多线程和并发.pdf

    Java多线程与并发编程是Java语言中用于处理多任务执行的关键技术,它能够帮助开发者设计出能够有效应对高并发请求的应用程序。在现代的线上(Online)和离线(Offline)应用中,合理利用多线程技术可以大幅提高系统...

    笔记_张孝祥_Java多线程与并发库高级应用

    张孝祥Java多线程与并发库高级应用学习笔记,很经典的学习多线程和并发的资料。张孝祥Java多线程讲义笔记由张孝祥亲自整理,很实用的。

    Java多线程与并发库高级应用视频教程22集

    资源名称:Java多线程与并发库高级应用视频教程22集资源目录:【】01传统线程技术回顾【】02传统定时器技术回顾【】03传统线程互斥技术【】04传统线程同步通信技术【】04传统线程同步通信技术_分割纪录【】05线程...

    Java_多线程与并发编程总结.doc

    Java多线程与并发编程是Java开发中至关重要的一部分,它涉及到如何高效地利用CPU资源,以实现程序的并行执行。在操作系统层面,多任务和多进程是通过分配不同的内存空间来实现的,而线程则共享同一进程的内存,这...

    java多线程并发控制[参照].pdf

    java多线程并发控制[参照].pdf

    java多线程并发

    java多线程并发的在新窗口

    多线程 高并发

    在IT领域,多线程和高并发是两个关键的概念,特别是在服务器端开发、分布式系统以及高性能计算中。这里,我们主要探讨的是如何通过编写多线程并发程序来优化应用程序的性能,提高系统的处理能力。 首先,多线程是指...

    人工智能-项目实践-多线程-Java多线程高并发实例.zip

    通过分析和运行这些代码,你将能够更深入地理解Java多线程在高并发场景下的实际运用,从而在你的人工智能项目中实现更高效、更稳定的数据处理。 总之,这个项目实例旨在帮助开发者掌握Java多线程技术,提升处理高...

    多线程,高并发.zip

    在IT领域,多线程和高并发是两个关键概念,特别是在Java编程中,它们对于构建高效、可扩展的系统至关重要。下面将详细解释这两个概念及其在Java中的实现和应用。 多线程是指在一个应用程序中同时运行多个独立的执行...

    Java入门到精通视频教程.课件.代码,30套Java开发项目代码,Java多线程与并发库高级应用视频教程,及电子书

    黑马+传智 Java入门到精通视频教程+课件+代码,30套Java开发项目代码,Java多线程与并发库高级应用视频教程,及电子书,面试题,开发工具等

    Java 高并发多线程编程系列案例代码

    Java 高并发多线程编程系列案例代码 & 教程 & 面试题集锦! !! 包括但不限于线程安全性, atomic包下相关类、CAS原理、Unsafe类、synchronized关键字等的使用及注意事项,

    java socket 多线程并发控制 hibernate mysql

    多线程并发控制是解决高并发问题的关键技术。Java提供了丰富的线程API,如Thread、Runnable接口,以及同步机制如synchronized关键字、Lock接口(如ReentrantLock)等。在设计多线程程序时,需要注意资源的竞争和死锁...

    黑马程序员_张孝祥_Java多线程与并发库 视频+代码+资料

    根据给定文件的信息,我们可以提炼出以下关于Java多线程与并发库的相关知识点: ### Java多线程基础 1. **线程的概念**:在Java中,线程是程序执行流的基本单元。一个标准的Java应用程序至少有一个线程,即主...

    多线程对文件读写操作(java)

    在Java编程中,多线程技术是提升程序执行效率的关键之一,特别是在进行文件读写操作时。本主题将深入探讨如何使用多线程来优化文件的读取和写入过程,以及需要注意的相关问题。 首先,我们需要理解单线程与多线程在...

    经典Java多线程与并发库高级应用

    在深入探讨Java多线程与并发库的高级应用前,有必要了解一些基础概念。Java线程是Java程序的基础,它代表程序中的一条执行线索或线路。在Java中创建线程有两种传统方式,一种是通过继承Thread类并覆盖其run方法来...

Global site tag (gtag.js) - Google Analytics