zoukankan      html  css  js  c++  java
  • Java,多个线程对同一个数据源的访问

    当多个线程对同一个数据源进行访问时,应对线程同步或加锁。
    为何?举个简单的例子:有一个共享的数据源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 ", 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 ", 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 ", dataSource);
    try
    {
    Thread.sleep(1);
    }
    catch (InterruptedException ex)
    {
    ex.printStackTrace();
    }
    finally
    {
    dataSource = t;
    out.printf("Task1 --- 自增后 --- dataSource: %d ", 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 ", dataSource);
    int t = dataSource - 1;
    try
    {
    Thread.sleep(10);
    dataSource = t;
    }
    catch (InterruptedException ex)
    {
    ex.printStackTrace();
    }
    finally
    {
    dataSource = t;
    out.printf("Task2 --- 自增后 --- dataSource: %d ", 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关键字对线程进行同步的方法,
    在此不做描述,其用法较简单,可自行百度^_^
  • 相关阅读:
    关于虚函数那点破事
    两个分析HTML网页的方法
    C#实现web信息自动抓取
    ASP:打造内容管理系统之模板技术乱谈
    猪的FLASH-大肚腩
    猪的FLASH-深呼吸
    ASP.NET正则对象初看。
    今天搜索了一下堕落的卖猪贩一词。
    个人形象Show-卡通图
    检测远程URL是否存在的三种方法
  • 原文地址:https://www.cnblogs.com/buyishi/p/8414054.html
Copyright © 2011-2022 走看看