Java ile uygulama geliştirirken bir çok kez file'dan okuma veya database'e baglanma islemlerini gerceklestiririz. Ozellikle bazı zamanlarda saniyeler suren bir gecikme meydana gelebilir bu tip okumaları yaparken. Ve de bu isi threadsiz yapiyorsak, malesef kullanici dostu olamamisiz demek ki...
Örneğin, bir butonumuz var ve bu buton veritabanına bağlanıp bize bir Connection nesnesini handle edecek. Thread kullanmaz isek butona bastığımızda buton kullanıcının veritabanına baglanma islemlerini gerceklestirme icerisinde oldugundan tepki veremeyecek ve kullanıcı programın kilitlendiğini zannedecektir. Böyle bir durumu önlemek için thread kullanılabilir.
Threadler çalışan proseslerin birer parçasıdırlar. Ingilizce anlamı ipliktir. Islemci bir anda sadece bir instruction işleyebilir. Thread ile instruction işlendiği anda disk okuması yapılabilir veya ekrana görüntü basılabilir. Çünkü bu işlemleri direk yapan cpu değildir. Biz de threadin bu özelliğinden yararlanacağız.
2 clasımız var. birinden diğer threadli clasımızı çağıracağız. Thread kullanılmayan classta thread kullanılan clası şu şekilde çağıracağız bizim örneğimiz için:
ff_1 =new FeedbackFrame_1(this, conn, sp, smsControl, smsReader, smsSender);
ff_1 bir FeedbackFrame_1 clasına ait nesne ve bu clasın contructoru görüldüğü gibi bir çok obje alıyo. Bunları siz uygulamanızın durumuna göre değiştirebilirsiniz. Peki FeedbackFrame_1.java dosyası nasıl bir dosya, içeriği ne:
import java.lang.reflect.*;
import java.awt.*;
import java.awt.event.*;
import java.sql.Connection;
import javax.swing.*;
import javax.comm.*;
/**
*
* @author Ahmet Fuat SUNGUR
* Sms kontrolunu saglamakla yukumludur. Soyleki serveri baslatmadan onceki ayarlarin bir thread
* aracigiyla yapilip, kullanici arayuzunu dondurmamak icin kullanilmis bir class'tir.
*/
public class FeedbackFrame_1 extends JFrame implements Runnable {
private SmsFlow sf;
private Thread t;
private JLabel label;
private int state;
private SerialPort sp;
private ComSettings comInstance;
private SmsControl sc;
private SmsReader sr;
private SmsSender ss;
private Connection conn;
public FeedbackFrame_1(SmsFlow sf,Connection conn, SerialPort sp,SmsControl sc, SmsReader sr, SmsSender ss) {
this.sf = sf;
this.sc = sc;
this.sr = sr;
this.ss = ss;
this.conn = conn;
this.sp = sp;
setupFrame();
t = new Thread(this);
t.start();
pack();
show();
}
private void setupFrame() {
label = new JLabel();
label.setPreferredSize(new Dimension(200,50));
Container c = getContentPane();
JButton stopButton = new JButton("Stop");
stopButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
error();
}
});
c.add(label, BorderLayout.NORTH);
c.add(stopButton, BorderLayout.SOUTH);
this.setTitle("Baglantilar deneniyor...");
}
private void setText(final String s) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
label.setText(s);
}
});
} catch (InterruptedException ie) {
error();
} catch (InvocationTargetException ite) {
error();
}
}
private void error() {
t.interrupt();
if (SwingUtilities.isEventDispatchThread())
closeDown();
else SwingUtilities.invokeLater(new Runnable() {
public void run() {
closeDown();
}
});
}
private void closeDown() {
sf.setupCancelled();
hide();
dispose();
}
public SmsSender getSmsSender()
{
return this.ss;
}
public SmsReader getSmsReader()
{
return this.sr;
}
public SmsControl getSmsControl()
{
return this.sc;
}
public void run() {
// Simulate connecting to server
try{
/////
// Streamlari ayarliyoruz. DataOutput, DataInput, OUTPUT Stream...
setText("Stream aciliyorr...");
try
{
Thread.sleep(1000);
}
catch (InterruptedException ie) {}
sc.setStreams();
// Ve GSM modemimizle konusmaya basliyoruz.
// ilk mesaji gonderdik.
setText("İlk mesajlar gonderiliyor...");
try
{
Thread.sleep(1000);
}
catch (InterruptedException ie) {}
sc.send("AT");
sc.expect("OK");
setText("Karakter mod destegi...");
try
{
Thread.sleep(1000);
}
catch (InterruptedException ie) {}
// Mesajlarin pdu formatinda degil de text formatinda olmasini istiyoruz.
sc.send("AT+CMGF=1");
sc.expect("OK");
// Ve simdi sira geldi mesajlari okumaya ve gelen mesajlari parse edip
// gerekli cevabi kullaniciya gondermeye.
// Simdi GSM modemimizdeki mesajlari okurken 1 okuyup, okudugumuz
// mesaji irdeleyip, yorumlayip, gereken cevabi uretip, bu cevabi
// bize mesaj gonderen kullaniciya geri iletmemiz gerekiyor.
// Burada bir producer consumer problemi var. Producer Reader kismi,
// Consumer Sender kismi oluyor. Yani bir mesaj ilk once okunacak, bu mesaj
// ile ilgili islemler yapilmadan 2. mesaj okunmaya gecilmeyecek.
// Bunu asmak icin threadlarden yararlandik ve producer consumer
// problemini çözmek için SmsProducerConsumer clasini olusturduk.
// SmsReader ve SmsSender classlari constructorlarinda bu SmsProducerConsumer
// classina ait nesneyi alirlar ve bu sayede gerekli senkronizasyon
// saglanmis olur.
/*SmsFirstSettings sfs = new SmsFirstSettings(smsControl);
sfs.start();
smsControl = sfs.getSmsControl(); */
setText("SMSReader ve SMSSender Class'lari hazirlaniyor...");
try
{
Thread.sleep(1000);
}
catch (InterruptedException ie) {}
SmsProducerConsumer smsProducerConsumer = new SmsProducerConsumer();
sr = new SmsReader(sp,conn,sf,sc,smsProducerConsumer);
ss = new SmsSender(sp,conn,sf,sc,smsProducerConsumer);
if (Thread.currentThread().isInterrupted())
return;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
sf.setupDone();
hide();
dispose();
}
});
}
catch(Exception e)
{}
}
public SerialPort getSerialPort()
{
return sp;
}
}
Burada önemli olan clasın Runnable interfacını implement etmesi, bunu unutmuyoruz.
ff_1 = new FeedbackFrame(...)
kodunu yazdığımızda yukarıdaki classın ilk run methodu çağırılıyor. Bu da bu husus açısından önemli...
Daha sonra yaptiğiniz baglantilari bir sekilde get etmeniz gerekiyor. o yüzden bu feedback clasına constructordan gonderdiginiz parametreleri get edebilecek metodlar eklemelisiniz...
iyi çalışmalar..
Örneğin, bir butonumuz var ve bu buton veritabanına bağlanıp bize bir Connection nesnesini handle edecek. Thread kullanmaz isek butona bastığımızda buton kullanıcının veritabanına baglanma islemlerini gerceklestirme icerisinde oldugundan tepki veremeyecek ve kullanıcı programın kilitlendiğini zannedecektir. Böyle bir durumu önlemek için thread kullanılabilir.
Threadler çalışan proseslerin birer parçasıdırlar. Ingilizce anlamı ipliktir. Islemci bir anda sadece bir instruction işleyebilir. Thread ile instruction işlendiği anda disk okuması yapılabilir veya ekrana görüntü basılabilir. Çünkü bu işlemleri direk yapan cpu değildir. Biz de threadin bu özelliğinden yararlanacağız.
2 clasımız var. birinden diğer threadli clasımızı çağıracağız. Thread kullanılmayan classta thread kullanılan clası şu şekilde çağıracağız bizim örneğimiz için:
ff_1 =new FeedbackFrame_1(this, conn, sp, smsControl, smsReader, smsSender);
ff_1 bir FeedbackFrame_1 clasına ait nesne ve bu clasın contructoru görüldüğü gibi bir çok obje alıyo. Bunları siz uygulamanızın durumuna göre değiştirebilirsiniz. Peki FeedbackFrame_1.java dosyası nasıl bir dosya, içeriği ne:
import java.lang.reflect.*;
import java.awt.*;
import java.awt.event.*;
import java.sql.Connection;
import javax.swing.*;
import javax.comm.*;
/**
*
* @author Ahmet Fuat SUNGUR
* Sms kontrolunu saglamakla yukumludur. Soyleki serveri baslatmadan onceki ayarlarin bir thread
* aracigiyla yapilip, kullanici arayuzunu dondurmamak icin kullanilmis bir class'tir.
*/
public class FeedbackFrame_1 extends JFrame implements Runnable {
private SmsFlow sf;
private Thread t;
private JLabel label;
private int state;
private SerialPort sp;
private ComSettings comInstance;
private SmsControl sc;
private SmsReader sr;
private SmsSender ss;
private Connection conn;
public FeedbackFrame_1(SmsFlow sf,Connection conn, SerialPort sp,SmsControl sc, SmsReader sr, SmsSender ss) {
this.sf = sf;
this.sc = sc;
this.sr = sr;
this.ss = ss;
this.conn = conn;
this.sp = sp;
setupFrame();
t = new Thread(this);
t.start();
pack();
show();
}
private void setupFrame() {
label = new JLabel();
label.setPreferredSize(new Dimension(200,50));
Container c = getContentPane();
JButton stopButton = new JButton("Stop");
stopButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
error();
}
});
c.add(label, BorderLayout.NORTH);
c.add(stopButton, BorderLayout.SOUTH);
this.setTitle("Baglantilar deneniyor...");
}
private void setText(final String s) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
label.setText(s);
}
});
} catch (InterruptedException ie) {
error();
} catch (InvocationTargetException ite) {
error();
}
}
private void error() {
t.interrupt();
if (SwingUtilities.isEventDispatchThread())
closeDown();
else SwingUtilities.invokeLater(new Runnable() {
public void run() {
closeDown();
}
});
}
private void closeDown() {
sf.setupCancelled();
hide();
dispose();
}
public SmsSender getSmsSender()
{
return this.ss;
}
public SmsReader getSmsReader()
{
return this.sr;
}
public SmsControl getSmsControl()
{
return this.sc;
}
public void run() {
// Simulate connecting to server
try{
/////
// Streamlari ayarliyoruz. DataOutput, DataInput, OUTPUT Stream...
setText("Stream aciliyorr...");
try
{
Thread.sleep(1000);
}
catch (InterruptedException ie) {}
sc.setStreams();
// Ve GSM modemimizle konusmaya basliyoruz.
// ilk mesaji gonderdik.
setText("İlk mesajlar gonderiliyor...");
try
{
Thread.sleep(1000);
}
catch (InterruptedException ie) {}
sc.send("AT");
sc.expect("OK");
setText("Karakter mod destegi...");
try
{
Thread.sleep(1000);
}
catch (InterruptedException ie) {}
// Mesajlarin pdu formatinda degil de text formatinda olmasini istiyoruz.
sc.send("AT+CMGF=1");
sc.expect("OK");
// Ve simdi sira geldi mesajlari okumaya ve gelen mesajlari parse edip
// gerekli cevabi kullaniciya gondermeye.
// Simdi GSM modemimizdeki mesajlari okurken 1 okuyup, okudugumuz
// mesaji irdeleyip, yorumlayip, gereken cevabi uretip, bu cevabi
// bize mesaj gonderen kullaniciya geri iletmemiz gerekiyor.
// Burada bir producer consumer problemi var. Producer Reader kismi,
// Consumer Sender kismi oluyor. Yani bir mesaj ilk once okunacak, bu mesaj
// ile ilgili islemler yapilmadan 2. mesaj okunmaya gecilmeyecek.
// Bunu asmak icin threadlarden yararlandik ve producer consumer
// problemini çözmek için SmsProducerConsumer clasini olusturduk.
// SmsReader ve SmsSender classlari constructorlarinda bu SmsProducerConsumer
// classina ait nesneyi alirlar ve bu sayede gerekli senkronizasyon
// saglanmis olur.
/*SmsFirstSettings sfs = new SmsFirstSettings(smsControl);
sfs.start();
smsControl = sfs.getSmsControl(); */
setText("SMSReader ve SMSSender Class'lari hazirlaniyor...");
try
{
Thread.sleep(1000);
}
catch (InterruptedException ie) {}
SmsProducerConsumer smsProducerConsumer = new SmsProducerConsumer();
sr = new SmsReader(sp,conn,sf,sc,smsProducerConsumer);
ss = new SmsSender(sp,conn,sf,sc,smsProducerConsumer);
if (Thread.currentThread().isInterrupted())
return;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
sf.setupDone();
hide();
dispose();
}
});
}
catch(Exception e)
{}
}
public SerialPort getSerialPort()
{
return sp;
}
}
Burada önemli olan clasın Runnable interfacını implement etmesi, bunu unutmuyoruz.
ff_1 = new FeedbackFrame(...)
kodunu yazdığımızda yukarıdaki classın ilk run methodu çağırılıyor. Bu da bu husus açısından önemli...
Daha sonra yaptiğiniz baglantilari bir sekilde get etmeniz gerekiyor. o yüzden bu feedback clasına constructordan gonderdiginiz parametreleri get edebilecek metodlar eklemelisiniz...
iyi çalışmalar..
Hiç yorum yok:
Yorum Gönder