当多个线程对同一个数据源进行访问时,应对线程同步或加锁。
为何?举个简单的例子:有一个共享的数据源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关键字对线程进行同步的方法,
在此不做描述,其用法较简单,可自行百度^_^

最新文章

  1. sql 触发器删除操作
  2. 计算机常用dos命令
  3. css3部分选择器整理
  4. java 27 - 8 反射之 通过反射来设置某个对象的某个属性为指定值
  5. Web API 接口
  6. paip.提升用户体验--radio图片选择器 easyui 实现..
  7. paip . 解决spring No unique bean of type [com.mijie.homi.search.service.index.MoodUserIndexService]
  8. 指针类型(C# 编程指南)
  9. 模板--&gt;中国剩余定理[互质版本]
  10. WebApi2官网学习记录---BSON
  11. 警告框和操作表(IOS开发)
  12. python chanllenge题解
  13. 【阿里聚安全&#183;安全周刊】500万台Android设备受感染|YouTube封杀枪支组装视频
  14. vue关闭代码检查eslint
  15. NLP入门(三)词形还原(Lemmatization)
  16. 1、通过eureka创建注册中心
  17. mysql 设置、更改、找回密码
  18. 线段树 || BZOJ1756: Vijos1083 小白逛公园 || P4513 小白逛公园
  19. JPEG
  20. # 20155214 2016-2017-2 《Java程序设计》第8周学习总结

热门文章

  1. nginx的简介和配置文件实例(一)
  2. BZOJ 2154 Crash的数字表格 ——莫比乌斯反演
  3. Numpy 花式索引
  4. 花匠(codevs 3289)
  5. NOIP[2015] 运输计划(codevs 4632)
  6. php——数据库操作之规范性
  7. Centos常用命名
  8. windows 下QT5.5+vs2013开发环境搭建
  9. ganglia-monitoring-centos-linux
  10. 【hibernate spring data jpa】执行了save()方法 sql语句也执行了,但是数据并未插入数据库中