Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Синхронизация в java(Нужна ли она здесь?)

1.6K
30 июня 2009 года
Shtirlitz
145 / / 31.07.2006
Доброго времени суток!
Возник вопрос следующего рода. Есть многопоточное приложение работающее с БД(mysql). Написал класс(DBAccess) через который происходят все запросы. Собственно, класс:
Код:
import java.sql.*;
import java.net.*;
import javax.xml.xpath.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
 
public class DBAccess {
    private  static Driver m_Driver;
 
    class ConnInfo {
        String Login;
        String Password;
        String Host;
        String Port;
    }
 
    ConnInfo m_ConnInfo;
 
    DBAccess(OptLoader Options) throws XPathExpressionException, SQLException, Exception {
        try{
            m_Driver=(Driver)URLClassLoader.newInstance(new URL[]{new URL("file:"+
                    Options.GetOptionByPath("Options/Directories/Basepath")+
                    Options.GetOptionByPath("Options/Database/Driver/Path"))}).loadClass("com.mysql.jdbc.Driver").newInstance();
 
            m_ConnInfo.Login=Options.GetOptionByPath("Options/Database/ConnInfo/Login");
            m_ConnInfo.Password=Options.GetOptionByPath("Options/Database/ConnInfo/Password");
            m_ConnInfo.Host=Options.GetOptionByPath("Options/Database/ConnInfo/Login");
            m_ConnInfo.Port=Options.GetOptionByPath("Options/Database/ConnInfo/Port");
 
            DriverManager.registerDriver(m_Driver);
            m_SharedConnection=m_Driver.connect("jdbc:mysql://"+
                    Options.GetOptionByPath("Options/Database/ConnInfo/Host")+
                    ":"+Options.GetOptionByPath("Options/Database/ConnInfo/Port")+
                    "?user="+Options.GetOptionByPath("Options/Database/ConnInfo/Login")+
                    "&password="+Options.GetOptionByPath("Options/Database/ConnInfo/Password"),null);
 
        }catch(SQLException sqlex){
            constants.MacroCatchException(sqlex,"SQLException in DBAccess constructor.");
        }catch(XPathExpressionException xpexex){
            constants.MacroCatchException(xpexex,"XPathExpressionException in DBAccess constructor.");
        }catch(Exception ex){
            constants.MacroCatchException(ex,"Unhandled exception in DBAccess constructor.");
        }
    }
 
    void Set(String SQLStatement) throws Exception{
        try{
            Connection t_Connection=m_Driver.connect("jdbc:mysql://"+
                    m_ConnInfo.Host+":"+m_ConnInfo.Port+"?user="+
                    m_ConnInfo.Login+"&password="+m_ConnInfo.Password,null);
            Statement t_Statement=t_Connection.CreateStatement();
            t_Statement.execute(SQLStatement);
           
        }catch(SQLException sqlex){
            constants.MacroCatchException(sqlex,"SQLException in Set: "+SQLStatement);
        }catch(Exception ex){
            constants.MacroCatchException(ex,"Unhandled exception in Set: "+SQLStatement);
        }
    }
}


Метод Set используется для создания отдельного соединения для каждого пользователя. Так вот есть ли необходимость делать его синхронизированным? Если нет, достаточно ли добавить:
 
Код:
...
synchronized(m_Driver){
   Connection t_Connection=m_Driver.connect("jdbc:mysql://"+
                    m_ConnInfo.Host+":"+m_ConnInfo.Port+"?user="+
                    m_ConnInfo.Login+"&password="+m_ConnInfo.Password,null);
}
...


Или необходимо синхронизировать весь метод целиком? Я не очень понимаю пока принципы синхрониции в Java, т.е. на каком уровне могут возникать ошибки. Моет ли возникнуть ошибка например при параллельном выполнении :
 
Код:
...
k++;
...


ведь на машинном уровне это кминимум 3 команды, и в С++ требует синхронихзации. а в литературе как правило рассматривается примерно одинаковая ситуация, поэтому буду благодарен за совет что либо конкретное почитать.
276
01 июля 2009 года
Rebbit
1.1K / / 01.08.2005
Простите что отвечаю не по теме поскольку не знаю нужна ли здесь синхронизацыя вообще, но хочу предостереч вас от некоторых возможных трудностей, которые могут возникнуть.
1. Создание конекшена дело трудоемкое, поетому создавать его для каждого запроса весьма розтратно относительно времени. Лутше еспользовать пул конекшенов.
2. Проганять каждый запрос на другом конекшене нехорошо и с той точки зрения что у вас пропадает возможность выполнять несколько запросов в одной транзакцыи.
37K
01 июля 2009 года
tanatoss
7 / / 18.05.2008
Синхронизация, на мой взгляд, не нужна поскольку драйвер у вас не мутабл. Разве что вы изменяете параметры драйвера от соединения к соединению (юзер, парольб схема и тп). В случае к++ синхронизация не нужна если к - локальная переменная. Если к - поле класса, то синхронизация нужна. В случае отдельного поля не обязательно писать:

 
Код:
class MyClass{
    private int k;

    public synchronized void accessK(){
         k++;
    }
}


достаточно использовать ключевое слово volatile (Java 5+). Поля объявленые с этим ключевым словом ведут себя как в блоке synchronized:

 
Код:
// эквивалентно предыдущему
class MyClass{
    private volatile int k;

    public void accessK(){
         k++;
    }
}
1.6K
02 июля 2009 года
Shtirlitz
145 / / 31.07.2006
Спасибо за ответы! Вот еще один вопрос в догонку, пусть есть объект(Object obj). Он допускает параллельное использование. Пусть имеется следующий класс:
 
Код:
public abstract Globals {
public static Object m_obj;
   InitGlobals(Object obj){
      m_Obj=obj;
   }
   public static Object GetObject(){
      return(m_Obj);
   }
}

Теперь в главном потоке я вызываю InitGobals(obj). Далее, уже в многопоточной среде, в каждом потоке делаю следующее:
 
Код:
...
Object ThObj=Globals.GetObject();
//Использую ThObj по назначению
...

Возможны ли здесь какие либо проблемы с многопоточностью? Как еще можно в разных потоках использовать один глобальный thread-safe объект? Заранее спасибо!
37K
02 июля 2009 года
tanatoss
7 / / 18.05.2008
проблемы могут быть если вы несколько раз вызовете InitGobals(obj) из разных потоков. В Globals.GetObject() проблем не будет.

Цитата:
Как еще можно в разных потоках использовать один глобальный thread-safe объект? Заранее спасибо!



вообще в данном случае рекомендую использовать синглетон паттерн и обязательно скрыть все поля класса:

Код:
class Globals{
    private static Globals instance;

    private Object someVariable;

    private Globals(){
         // init all global variables
         // при необходимости заключить в synchronized блок
    }

    public static Globals getInstance(){
        if(instance==null){
            instance = new Globals();
        }
        return instance;
    }

    public Object getSomeVariable(){
        return someVariable;
    }
}

Использование:
 
Код:
//...
Globals.getInstance().getSomeVariable();
//...

При условии что someVariable изменяется только при инициализации - данный подход полностью tread-safe.
1.6K
04 июля 2009 года
Shtirlitz
145 / / 31.07.2006
Сапсибо! Я так и сделал!
5
05 июля 2009 года
hardcase
4.5K / / 09.08.2005
Цитата: tanatoss
При условии что someVariable изменяется только при инициализации - данный подход полностью tread-safe.


При некотором стечении обстоятельств (из параллельных потоков тягается getInstance() в "первый" раз) может быть создано несколько экземпляров Globals - тот что был создан последним будет сохранен ссылкой instance, остальные будут "забыты". Так что в блок синхронизации нужно заключать метод getInstance(), а не конструктор Globals.

1.6K
05 июля 2009 года
Shtirlitz
145 / / 31.07.2006
Благо в первый раз у меня все в главном потоке инициализируется. Далее лишь используется параллельно...
276
16 июля 2009 года
Rebbit
1.1K / / 01.08.2005
Цитата: hardcase
Так что в блок синхронизации нужно заключать метод getInstance(), а не конструктор Globals.



Не самое лутшее решение.
Получим плуг при частом вызове getInstance.
Лутше примерно так (пишу без компиляцыи)

Код:
class Globals{
    private static Globals instance;

    private Globals(){
         // init all global variables
    }

    private static synchronized createInstrance() {
        if(instance==null){
            instance = new Globals();
        }
    }

    public static Globals getInstance(){
        if(instance==null){
            createInstrance();
        }
        return instance;
    }

}
Тоесть с двойной проверкой синхронизируем только создание екземпляра. Но такой подход нужен не так часто.
Если вы знаете что екземпляр создается быстро и создастса в любом случае - проще написать
 
Код:
class Globals{
    private static Globals instance = new Globals();
    ....
}
5
16 июля 2009 года
hardcase
4.5K / / 09.08.2005
Цитата: Rebbit
Лутше примерно так (пишу без компиляцыи)

Ну эт железобетонная классика ;)

276
20 июля 2009 года
Rebbit
1.1K / / 01.08.2005
Цитата: hardcase
Ну эт железобетонная классика ;)


Ну дик я на авторство и не претендую. Просто на домашнем дайлапе быстрее самому настрочить чем ссылку искать :)

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог