当多个线程对同一个数据源进行访问时,应对线程同步或加锁。
为何?举个简单的例子:有一个共享的数据源dataSource,其值为0。有两个线程,Thread1和Thread2。
Thread1的任务是将dataSource连续自增10次,
Thread2的任务是将dataSource连续自减10次,
当两个线程的任务都完成时,最终的dataSource的值应为0,事实上,可能不为0,请看示例1:

import static java.lang.System.out;
public class LockTest1
{
private static int dataSource;
private static class Task1 implements Runnable
{
public void run()
{
for (int i = 0; i < 10; ++i)
{
out.printf("Task1 --- dataSource: %d\n", dataSource);
int t = dataSource + 1;

try
{
Thread.sleep(1);
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
finally
{
dataSource = t;
}
}
}
}
private static class Task2 implements Runnable
{
public void run()
{
for (int i = 0; i < 10; ++i)
{
out.printf("Task2 --- dataSource: %d\n", dataSource);
int t = dataSource - 1;
try
{
Thread.sleep(10);
dataSource = t;
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
finally
{
dataSource = t;
}
}
}
}
public static void main(String[] args) throws InterruptedException
{
Thread thread1 = new Thread(new Task1());
Thread thread2 = new Thread(new Task2());
thread1.start();
thread2.start();
Thread.sleep(1000);
out.printf("The value of dataSource is %d.", dataSource);
}
}

最终的结果出人意料,dataSource的值不为0。
线程之间的切换执行,在访问同一数据源时会出差错。
如何避免这种错误?加锁或同步。对示例1进行修改,请看示例2:

import static java.lang.System.out;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class LockTest2
{
private static int dataSource;
private static ReentrantReadWriteLock.WriteLock lock = new ReentrantReadWriteLock().writeLock();
private static class Task1 implements Runnable
{
public void run()
{
lock.lock();
for (int i = 0; i < 10; ++i)
{
int t = dataSource + 1;
out.printf("Task1 --- 自增前 --- dataSource: %d\n", dataSource);
try
{
Thread.sleep(1);
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
finally
{
dataSource = t;
out.printf("Task1 --- 自增后 --- dataSource: %d\n", dataSource);
}
}
lock.unlock();
}
}
private static class Task2 implements Runnable
{
public void run()
{
lock.lock();
for (int i = 0; i < 10; ++i)
{
out.printf("Task2 --- 自增前 --- dataSource: %d\n", dataSource);
int t = dataSource - 1;
try
{
Thread.sleep(10);
dataSource = t;
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
finally
{
dataSource = t;
out.printf("Task2 --- 自增后 --- dataSource: %d\n", dataSource);
}
}
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException
{
Thread thread1 = new Thread(new Task1());
Thread thread2 = new Thread(new Task2());
thread1.start();
thread2.start();
Thread.sleep(300);
//睡眠一段时间,确保thread1和thread2执行完毕后再打印dataSource的值
out.printf("dataSource的值为%d.", dataSource);
}
}

此示例中,多个线程对同一数据源的修改可能会造成混乱,
所以我使用ReentrantReadWriteLock.WriteLock(写锁),
来保证每个线程对数据源修改时不被其他线程干扰。
 
对于另外一种使用synchronized关键字对线程进行同步的方法,
在此不做描述,其用法较简单,可自行百度^_^

Java,多个线程对同一个数据源的访问的更多相关文章

  1. 第36节:Java当中的线程

    Java当中的线程 Java当中的线程,进程和线程的关系?进程就是线程吗?不是的.线程的运行,和方法. 多线程和多进程,多进程为在操作系统中同时进行多个应用程序,如你的电脑可以同时听音乐,同时上网,手 ...

  2. java多线程之线程安全

    线程安全和非线程安全是多线程的经典问题,非线程安全会在多个线程对同一个对象并发访问时发生. 注意1: 非线程安全的问题存在于实例变量中,如果是方法内部的私有变量,则不存在非线程安全问题. 实例变量是对 ...

  3. Java多线程 3 线程同步

    在之前,已经学习到了线程的创建和状态控制,但是每个线程之间几乎都没有什么太大的联系.可是有的时候,可能存在多个线程多同一个数据进行操作,这样,可能就会引用各种奇怪的问题.现在就来学习多线程对数据访问的 ...

  4. JAVA中的线程安全与非线程安全

    原文:http://blog.csdn.net/xiao__gui/article/details/8934832 ArrayList和Vector有什么区别?HashMap和HashTable有什么 ...

  5. Java面试题-线程安全

    1. 什么叫线程安全?servlet是线程安全吗?       答:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码.如果每次运行结果和单线程运行的结果是一样的,而且其他 ...

  6. Java并发3-多线程面试题

    1) 什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速. 2) 线程和进程有什 ...

  7. Java中的线程Thread总结

    首先来看一张图,下面这张图很清晰的说明了线程的状态与Thread中的各个方法之间的关系,很经典的! 在Java中创建线程有两种方法:使用Thread类和使用Runnable接口. 要注意的是Threa ...

  8. Java值创建线程的两种方式对比

    在Java中创建线程的方式有两种,第一种是直接继承Thead类,另一种是实现Runable接口.那么这两种方式孰优孰劣呢? 采用继承Thead类实现多线程: 优势:编写简单,如果需要访问当前线程,只需 ...

  9. Java多线程之线程其他类

    Java多线程之线程其他类 实际编码中除了前面讲到的常用的类之外,还有几个其他类也有可能用得到,这里来统一整理一下: 1,Callable接口和Future接口 JDK1.5以后提供了上面这2个接口, ...

随机推荐

  1. BZOJ 2190 [SDOI2008]仪仗队 ——Dirichlet积

    [题目分析] 考虑斜率为0和斜率不存在的两条线上只能看到3人. 其余的人能被看见,当且仅当gcd(x,y)=1 ,然后拿卷积算一算 发现就是欧拉函数的前缀和的二倍. 注意2的情况要特判. [代码] # ...

  2. SPOJ QTREE3 Query on a tree again! ——Link-Cut Tree

    [题目分析] QTREE2,一看是倍增算法,太懒了,不写了.( ̄_, ̄ ) QTREE3,树链剖分可以做,发现链上的问题LCT也很好做. 要是子树问题貌似可以DFS序. 然后就成LCT模板题了. 考前 ...

  3. 【FFT求卷积】Problem D. Duel

    [AC] #include <stdio.h> #include <iostream> #include <string.h> #include <algor ...

  4. 转载:LINK:fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏

    原文地址:http://yacare.iteye.com/blog/2010049 很多伙伴在更新VS2010,或者卸载VS2012安装2010后,建立Win32 Console Project/MF ...

  5. POJ 3099 Go Go Gorelians

    http://poj.org/problem?id=3099 树的重心:找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心 求树的重心 如何在点中构造符合条件的树 得到树后 从 ...

  6. vba比较日期大小,定义日期;vba让excel保存

    Private Sub CommandButton1_Click()Dim i, j As IntegerDim a As Datea = #10/1/2013#j = 2i = 2' If  Wor ...

  7. 如何选择 IT 技术书籍

    ★第1招:看网上评论 首先,上一些权威的图书网站,看看大伙儿的评价如何(要相信群众的眼睛是雪亮的).对于英文书籍,我一般上亚马逊网站去看看:中文书籍则上豆瓣网.这两个网站都提供星级评分,一般 > ...

  8. iOS 内存管理策略

    内存管理策略(memory Management Policy) NSObject protocol中定义的的方法和标准命名惯例一起提供了一个引用计数环境,内存管理的基本模式处于这个环境中.NSObj ...

  9. 什么场景应该用 MongoDB ?

    摘要: 月初在云栖社区上发起了一个 MongoDB 使用场景及运维管理问题交流探讨 的技术话题,有近5000人关注了该话题讨论,这里就 MongoDB 的使用场景做个简单的总结,谈谈什么场景该用 Mo ...

  10. BUPT复试专题—科学计算器(2009)

    题目描述 给你一个不带括号的表达式,这个表达式只包含加.减.乘.除,请求出这个表 达式的最后结果,最后结果一定是整数: 输入 一个数学表达式,只包括数字,数字保证是非负整数,以及五种运算符 " ...