Obraz zawierający tekst, Czcionka, Grafika

Opis wygenerowany automatycznie 

Kierunek Informatyka

 

Instrukcja do ćwiczeń laboratoryjnych nr:

11

Nazwa przedmiotu:
Programowanie w języku Java

Temat: Wyjątki  (część 1)  i animacje

Tryb studiów: stacjonarny

Czas trwanie ćw.

2x45 min

Autor materiałów: dr Marcin Skuba

 

 

1.      Treści programowe:
Wątki, programowanie współbieżne, główny wątek aplikacji, animacje, metody graficzne.

2.      Cel zajęć:

Zrozumienie mechanizmów programowania współbieżnego. Opanowanie umiejętności wykorzystania wątków do animacji obiektów graficznych. Praktyczne wykorzystanie narzędzi graficznych w Java2. 

 

3. Materiały


Wątek jest reprezentowany prze obiekt utworzony z klasy Thread. Konstruktor jako argument pobiera klasę z zaimplementowanym interfejsem Runnable lub instancję tego interfejsu z metodą run.

 

Wątki (Threads) w Javie są podstawowym mechanizmem pozwalającym na wykonywanie wielu zadań równolegle (lub współbieżnie) w ramach jednego programu (procesu).

 

Podstawowe Informacje o Wątkach

·       Wątek to pojedyncza sekwencja wykonywania wewnątrz programu. Każdy program Javy, zaraz po uruchomieniu, posiada co najmniej jeden wątek, zwany głównym wątkiem (main thread).

·       Wielowątkowość (Multithreading): Pozwala to programiście na wykorzystanie mocy współczesnych procesorów wielordzeniowych, co znacznie zwiększa wydajność aplikacji, szczególnie przy zadaniach wymagających długiego oczekiwania (np. operacje wejścia/wyjścia, komunikacja sieciowa).

·       Tworzenie Wątków: W Javie wątki można tworzyć na dwa główne sposoby:

1.      Implementując interfejs Runnable i przekazując obiekt do konstruktora klasy Thread. Jest to preferowany sposób, ponieważ pozwala klasie dziedziczyć z innej klasy.

2.      Dziedzicząc po klasie Thread i nadpisując metodę run().

·       Metoda run() i start(): Logika, która ma być wykonywana w nowym wątku, musi znajdować się w metodzie run(). Aby faktycznie uruchomić nowy, współbieżny wątek, należy wywołać metodę start() na obiekcie Thread. Wywołanie bezpośrednio run() spowoduje wykonanie kodu w bieżącym wątku, a nie w nowym.

·       Synchronizacja: Wielowątkowość wiąże się z ryzykiem powstawania warunków wyścigu (race conditions), gdy wiele wątków próbuje jednocześnie modyfikować ten sam zasób. Java rozwiązuje ten problem za pomocą mechanizmów synchronizacji, takich jak słowo kluczowe synchronized (dla metod lub bloków kodu) oraz klasy z pakietu java.util.concurrent (np. Lock, Semaphore).

        
thread = new Thread(this);

 

Interfejs Runnable:

Konstrukcja metody abstrakcyjnej run interfejsu Runnable:

 

    @Override
    public void run() {
    }

 

Pętla niekończąca się uruchomiona w nowym wątku przez metodę run oraz opóźnienie równe jednej sekundzie:

 

    @Override
    public void run() {
        while (true){
                   
            // miejsce na kod wywoływany w oddzielnym wątku cyklicznie co jedną sekundę 
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

 

 Aby uruchomić metodę run czyli nowy wątek należy z obiektu wątku wywołać metodę start.:

 

        thread.start();

 

 

Przykład 1

------------------------------------------------------------------------------------------------------------------------------------------
Przykład aplikacji, w której pojawia się problem polegający na braku możliwości uruchomienia dwóch niekończących się pętli.

 

class Animacja extends JFrame{
 
    Animacja(){
        super("Animacja");
        setBounds(100,100,450,100);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        PanelAnimacja  anim  = new PanelAnimacja();
 
        setContentPane(anim);
        setVisible(true);
        anim.scroll();
    }
    static public void main (String arg[]){
           new Animacja();
        while(true){         // Pętla pierwsza 
            System.out.print("*");
            try{
                Thread.sleep(1000);
            }catch (InterruptedException e){}
        }
    }
}

 

import javax.swing.*;
import java.awt.*;
 
class PanelAnimacja extends JPanel{
 
    int y=80;
    String tekst[] = {" Wątki są częściami programu, które działają niezależnie ",
            " od innych zadań realizowanych przez dany program.",
            " Taka właściwość jest często określana mianem wielozadaniowości",
            " ponieważ program jednocześnie realizuje więcej niż jedno zadanie.  "};
 
    Font font;
 
    PanelAnimacja(){
        font = new Font("Arial", Font.BOLD, 12);
 
    }
    public void scroll (){
        while(true){  //Pętla druga 
           y--;
 
            if (y < -80)
               y=80;
            repaint();
           try{
                Thread.sleep(60);
            }catch (InterruptedException e){}
        }
   }
 
    public void paintComponent(Graphics g){
        Graphics2D g2D = (Graphics2D)g;
        g2D.setColor(getBackground());
        g2D.fillRect(0,0,getSize().width, getSize().height);
        g2D.setColor(Color.black);
        g2D.setFont(font);
        for(int i=0; i<tekst.length; i++)
            g2D.drawString(tekst[i], 10, y+(i*20));
    }
}

 

 

Poniższy przykład rozwiązuje wspomniany problem przez zastosowanie oddzielnego wątku, w którym uruchomiona została jedna niekończąca się pętla oraz druga w głównym wątku aplikacji.

 

import javax.swing.*;
 
class Animacja extends JFrame{
 
    Animacja(){
        super("Animacja");
        setBounds(100,100,450,100);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        PanelAnimacja  anim  = new PanelAnimacja();
 
        setContentPane(anim);
        setVisible(true);
    }
    static public void main (String arg[]){
           new Animacja();
        while(true){
            System.out.print("*");
            try{
                Thread.sleep(1000);
            }catch (InterruptedException e){}
        }
    }
}

 

 

import javax.swing.*;
import java.awt.*;
 
class PanelAnimacja extends JPanel implements Runnable{
 
    int y=80;
    String tekst[] = {" Wątki są częściami programu, które działają niezależnie ",
            " od innych zadań realizowanych przez dany program.",
            " Taka właściwość jest często określana mianem wielozadaniowości",
            " ponieważ program jednocześnie realizuje więcej niż jedno zadanie.  "};
 
    Font font;
 
    PanelAnimacja(){
        font = new Font("Arial", Font.BOLD, 12);
        Thread watek = new Thread(this);
        watek.start();
    }
    public void run (){
        while(true){
            y--;
            if (y < -80)
                y=80;
            repaint();
 
            try{
                Thread.sleep(60);
            }catch (InterruptedException e){}
        }
    }
    public void paintComponent(Graphics g){
        Graphics2D g2D = (Graphics2D)g;
        g2D.setColor(getBackground());
        g2D.fillRect(0,0,getSize().width, getSize().height);
        g2D.setColor(Color.black);
        g2D.setFont(font);
        for(int i=0; i<tekst.length; i++)
            g2D.drawString(tekst[i], 10, y+(i*20));
    }
}

 

Wykorzystanie czterech wątków aplikacji. Trzy panele oraz wątek główny aplikacji, w którym rysowane są gwiazdki

 

import javax.swing.*;
import java.awt.*;
 
class Animacja extends JFrame{
 
    Animacja(){
        super("Animacja");
        setBounds(100,100,450,300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel panel = new JPanel(new GridLayout(3,1));
        PanelAnimacja  anim1  = new PanelAnimacja(50);
        PanelAnimacja  anim2  = new PanelAnimacja(120);
        PanelAnimacja  anim3  = new PanelAnimacja(200);
        panel.add(anim1);
        panel.add(anim2);
        panel.add(anim3);
        setContentPane(panel);
        setVisible(true);
    }
    static public void main (String arg[]){
           new Animacja();
        while(true){
            System.out.print("*");
            try{
                Thread.sleep(1000);
            }catch (InterruptedException e){}
        }
    }
}

 

import javax.swing.*;
import java.awt.*;
 
class PanelAnimacja extends JPanel implements Runnable{
 
    int y=80;
    String tekst[] = {" Wątki są częściami programu, które działają niezależnie ",
            " od innych zadań realizowanych przez dany program.",
            " Taka właściwość jest często określana mianem wielozadaniowości",
           " ponieważ program jednocześnie realizuje więcej niż jedno zadanie.  "};
 
    Font font;
    int czas=0;
    PanelAnimacja(int czas){
        font = new Font("Arial", Font.BOLD, 12);
        this.czas=czas;
        Thread watek = new Thread(this);
        watek.start();
    }
    public void run (){
        while(true){
            y--;
            if (y < -80)
                y=80;
            repaint();
 
            try{
                Thread.sleep(czas);
            }catch (InterruptedException e){}
        }
    }
 
 
    public void paintComponent(Graphics g){
        Graphics2D g2D = (Graphics2D)g;
        g2D.setColor(getBackground());
        g2D.fillRect(0,0,getSize().width, getSize().height);
        g2D.setColor(Color.black);
        g2D.setFont(font);
        for(int i=0; i<tekst.length; i++)
            g2D.drawString(tekst[i], 10, y+(i*20));
    }
}

 

 

 

Przykład 2

-------------------------------------------------------------------------------------------

Przykład aplikacji ukazujący programowanie współbieżne.

 

import javax.swing.*;
import
java.awt.*;

public class
Buttons extends JFrame {
   
final int MAX=25;
   
Buttons(){
       
super("Buttons");
       
setBounds(100,100,500,500);
       
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       
JPanel panel = new JPanel(new GridLayout(5,5));

        for
(int i=0; i<MAX; i++){
            NewButton b =
new NewButton();
           
panel.add(b);
       
}

        setContentPane(panel)
;
       
setVisible(true);
   
}

   
public static void main(String[] args) {
       
new Buttons();
   
}
}

 

 

Zmodyfikowana klasa przycisku:

 

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
 
public class NewButton extends JButton implements Runnable, ActionListener {
    Thread thread;
 
    NewButton(){
        thread = new Thread(this);
        setBackground(Color.blue);
        addActionListener(this);
   }
 
    @Override
    public void run() {
        while (true){
            if(getBackground()==Color.blue)
                setBackground(Color.red);
            else
             setBackground(Color.blue);
 
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
 
    @Override
    public void actionPerformed(ActionEvent e) {
        if(!thread.isAlive()) // zabezpieczenie przed ponownym uruchomieniem wątku co spowodowałoby błąd. 
        thread.start();
    }
}

 

 

Przykład wykorzystania wątku bez implementacji interfejsu:

 

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
 
public class NewButton extends JButton implements ActionListener {
    Thread thread;
 
    NewButton(){
        setBackground(Color.blue);
        addActionListener(this);
    }
 
    @Override
    public void actionPerformed(ActionEvent e) {
 
        if(thread==null) {
            thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        if (getBackground() == Color.blue)
                            setBackground(Color.red);
                        else
                            setBackground(Color.blue);
 
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
 
            if (!thread.isAlive())
                thread.start();
        }
    }
}

 

 

4. Zadania


Zadanie 1

Wynikiem działania programu jest animacja (gra), w której „piłka” odbija się od brzegów ramki aplikacji  oraz do belki na dole panelu (na ukos).

Belka poruszana jest razem z myszą po osi Y.
Program składa się z dwóch klas:
PanelAnimacji (dziedziczony z JPanel), który posiada oddzielny wątek animujący piłkę,
Animacja – główna klasa programu.