繁体   English   中英

如何以单例模式同步两种方法

[英]How to synchronize two methods in a singleton pattern

我已经根据单例模式创建了一个数据库对象。 数据库对象包含2个方法: connect()update()

该更新应运行在多线程上,这意味着我无法在update方法签名中放置synchronized (我希望用户一次不能同时访问它)。

我的问题是,我要确保根据以下流程确定两个方案:

  1. 线程1(user1)是第一个创建数据库实例的线程,线程2(user2)对此数据库调用connect()update()方法-即使在user2正在执行操作时,也不应提供NullPointerException从user1进行的update()连接未完成。

  2. update()不应包含synchronized (由于上述原因)。 感谢所有的帮手!

SingeltonDB

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

    public class SingeltonDB {
        private static DBconnImpl db = null;
        private static SingeltonDB singalDb = null;
          Lock dbLock;

        private SingeltonDB(String username, String password) {
            db = new DBconnImpl();
        }

        public static boolean isOpen() {
            return (db != null);
        }

        public synchronized static SingeltonDB getInstance(String username,
                String password) throws Exception {

            if (db != null) {
                throw (new Exception("The database is  open"));
            } else {
                System.out.println("The database is now open");
                singalDb = new SingeltonDB(username, password);
            }
            db.connect(username, password);
            System.out.println("The database was connected");

            return singalDb;
        }

        public synchronized static SingeltonDB getInstance() throws Exception {
            if (db == null) {
                throw (new Exception("The database is not open"));
            }

            return singalDb;
        }

        public void create(String tableName) throws Exception {
            dbLock = new ReentrantLock();
            dbLock.lock();
            db.create(tableName);
            dbLock.unlock();
        }

        public  User query(String tableName, int rowID) throws Exception {
            if (db == null) {
                System.out.println("Error: the database is not open");
                return null;
            }
            return (db.query(tableName, rowID));
        }

        public  void update(String tableName, User user) throws Exception {
            if (db == null) {
                System.out.println("Error: the database is not open");
                return;
            }
            db.update(tableName, user);
        }

    }

主要

public class Main {
    public static void main(String[] args) throws Exception {

        Creator cr= new Creator(new UserContorller());
        Thread t1 = new Thread(cr);
        t1.start();
        Producer pr = new Producer(new UserContorller());
        Thread t2 = new Thread(pr);
        t2.start();

        /*
         * Consumer cn = new Consumer(new UserContorller()); Thread t2 = new
         * Thread(cn); t2.start();
         */
    }
}

class Creator implements Runnable {
    UserContorller uc;

    public Creator(UserContorller uc) {
        this.uc = uc;
    }

    @Override
    public void run() {
        try {
            uc = new UserContorller("MyAccount", "123");
            uc.createTable("table1");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class Producer implements Runnable {
    UserContorller uc;

    public Producer(UserContorller uc) {
        this.uc = uc;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                uc.saveUser("table1", i, "User", i);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

class Consumer implements Runnable {
    UserContorller uc;

    public Consumer(UserContorller uc) {
        this.uc = uc;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                System.out.println(uc.getUser("table1", i));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

创建单例时,连接一次(也许在构造函数中)。 有一个同步的静态方法( getInstance或其他方法),该方法检查实例是否存在, 根据需要创建连接,然后返回该实例。 通过遵循此协议,可以确保线程始终获得准备使用的已连接Db对象。

用户将调用该方法来获取单例实例,并调用update或他们想要在其上进行的任何操作,而无需同步该实例。

注意:下面的帖子是针对两个用户使用相同凭据(从他们隐藏)来连接到数据库的角度而写的。 如果用户使用不同的凭据,则单例db对象的想法是没有目的的,每个用户都应该有自己的连接对象,然后,当然,连接详细信息会通过程序中代表用户的内容从用户传递到Db(此处线程实例)。

您提供的实现中的主要问题是getinstance方法要求其调用者知道连接详细信息,或者假定连接已经完成。 但是,线程既不能也不应该事先知道是否已经打开了Db-从设计的角度来看,让他们承担明确打开它的责任是错误的。 这些线程是工作线程,它们不必关心Db配置细节。

处理这种情况的唯一明智的方法是直接将这些配置参数保存在Db对象中,或者最好由另一个负责提供它的对象(这是工厂模式)保存。

但是,如果您希望首先使代码以最小的更改来工作,请删除参数较少的getinstance方法,让任何线程要求Db对​​象使用该方法的其余变体,传递正确的参数,然后将其更改为返回实例(如果存在),否则创建它,而不会引发异常。 我相信这就是@Dima一直试图在他的回答中解释的内容。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM