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);
}
}
}
Синхронизация в java(Нужна ли она здесь?)
Возник вопрос следующего рода. Есть многопоточное приложение работающее с БД(mysql). Написал класс(DBAccess) через который происходят все запросы. Собственно, класс:
Код:
Метод 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);
}
...
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++;
...
k++;
...
ведь на машинном уровне это кминимум 3 команды, и в С++ требует синхронихзации. а в литературе как правило рассматривается примерно одинаковая ситуация, поэтому буду благодарен за совет что либо конкретное почитать.
1. Создание конекшена дело трудоемкое, поетому создавать его для каждого запроса весьма розтратно относительно времени. Лутше еспользовать пул конекшенов.
2. Проганять каждый запрос на другом конекшене нехорошо и с той точки зрения что у вас пропадает возможность выполнять несколько запросов в одной транзакцыи.
Код:
class MyClass{
private int k;
public synchronized void accessK(){
k++;
}
}
private int k;
public synchronized void accessK(){
k++;
}
}
достаточно использовать ключевое слово volatile (Java 5+). Поля объявленые с этим ключевым словом ведут себя как в блоке synchronized:
Код:
// эквивалентно предыдущему
class MyClass{
private volatile int k;
public void accessK(){
k++;
}
}
class MyClass{
private volatile int k;
public void accessK(){
k++;
}
}
Код:
public abstract Globals {
public static Object m_obj;
InitGlobals(Object obj){
m_Obj=obj;
}
public static Object GetObject(){
return(m_Obj);
}
}
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 по назначению
...
Object ThObj=Globals.GetObject();
//Использую ThObj по назначению
...
Возможны ли здесь какие либо проблемы с многопоточностью? Как еще можно в разных потоках использовать один глобальный thread-safe объект? Заранее спасибо!
Цитата:
Как еще можно в разных потоках использовать один глобальный 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;
}
}
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();
//...
Globals.getInstance().getSomeVariable();
//...
При условии что someVariable изменяется только при инициализации - данный подход полностью tread-safe.
Сапсибо! Я так и сделал!
Цитата: tanatoss
При условии что someVariable изменяется только при инициализации - данный подход полностью tread-safe.
При некотором стечении обстоятельств (из параллельных потоков тягается getInstance() в "первый" раз) может быть создано несколько экземпляров Globals - тот что был создан последним будет сохранен ссылкой instance, остальные будут "забыты". Так что в блок синхронизации нужно заключать метод getInstance(), а не конструктор Globals.
Благо в первый раз у меня все в главном потоке инициализируется. Далее лишь используется параллельно...
Цитата: 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;
}
}
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();
....
}
private static Globals instance = new Globals();
....
}
Цитата: Rebbit
Лутше примерно так (пишу без компиляцыи)
Ну эт железобетонная классика ;)
Цитата: hardcase
Ну эт железобетонная классика ;)
Ну дик я на авторство и не претендую. Просто на домашнем дайлапе быстрее самому настрочить чем ссылку искать :)