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关键字对线程进行同步的方法,
    在此不做描述,其用法较简单,可自行百度^_^
  • 相关阅读:
    C语言数组和字符串函数
    C语言控制语句
    C语言输入输出函数
    C语言运算符
    C语言数据类型
    嵌入式开发基础知识
    VI编辑器的使用
    Linux文件系统和目录相关命令
    前段之必学(转载)
    26个高效工作的小技巧(转载)
  • 原文地址:https://www.cnblogs.com/buyishi/p/8414054.html
Copyright © 2011-2022 走看看