トップ・ページの表示 注意書きの表示 掲示板に書き込む前に必ず この ”注意書き”を お読み下さい.

"沙羅"

★この掲示板は書き込みを停止いたしました 。
記事の書き込みはリンク・ページの表示 http://ashtarte.hotcom-web.com/utf8/smt.cgi?r+rpr/ を ご利用 下さい。

   
   

ページの表示順:{ 新しい順/ 古い順}.
初期・ページの表示・位置:{ 先頭ページ/ 末尾ページ}.
1ページ内のスレッド表示数:







<Number>: [00000632]  <Date>: 2023/02/21 21:39:21
<Title>: Javaデモ/Swing「Sinグラフを横スクロールさせる、Thread、排他制御(synchronized)、最適化の抑制(volatile)」(007)
<Name>: amanojaku@管理人

Sin グラフを横スクロールさせる、ComboBox で「波長の数、カラー」を指定して、[Make]ボタンで新しい Sin グラフを追加できます。
2つ以上の Sin グラフを表示すると、白色で合成波を表示します。
なお、SinGraph の Draw メソッドは使用していません。

このデモは「Concurrency Utilities」のスレッドを使用しています。
排他制御(synchronized)、最適化の抑制(volatile)も使用しており、特に排他制御(synchronized)は必要最小限にするように熟慮しています。

(知らぬ間に)古いタイプのThreadが非推奨に?、(正式な非推奨では無いかもしれないが)そんなクズみたいなモノを何時までも使わないでくれよ、って話。
スレッドは「Concurrency Utilities」のスレッドが強く推奨されます。
なお 新しいJavaでも古いタイプのThreadを使ってたら意味ないので注意して下さい、ただし素のJavaとAndroid Javaは内部的には別モノなので、Android Javaなら普通の(古いタイプの)Threadでおkです。

下記 動画を参照して下さい、青色がCUPの未使用率、緑色がCUPの使用率だと思われます。
その動画のコンソール入力に注目すると、「ConcurrencyTest」を実行すると、CUPの使用率が ほぼ100%になり、圧倒的に効率が上がります(逆に言うと古いタイプのThreadが如何にクズかと言うことでも有りますが)。

Concurrency Utilities for EE 7
https://yoshio3.com/2013/05/15/concurrency-utilities-for-ee-7/


【SinGraph007.java】

import java.awt.EventQueue;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

import java.awt.BorderLayout;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Color;

import java.util.ArrayList;

import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class SinGraph007 extends JFrame {
  static String sAppTitle = "Application SinGraph 7.";
  static boolean lApplication = false; // true;
  static SinGraph007 oAppFrame;
  JPanel content;

  // Thread oAppThread;
  int iLayoutX, iLayoutY;
  CanvasObj oCanvas;
  int iCanvasWidth, iCanvasHeight;
  JComboBox ccbSinGraph_WaveQnt;
  int iCbSinGraph_WaveQnt_Width, iCbSinGraph_WaveQnt_Height;
  JComboBox ccbSinGraph_Color;
  int iCbSinGraph_Color_Width, iCbSinGraph_Color_Height;
  Color[] d1oCbSinGraph_ColorSets;
  JButton cbtSinGraph_Make;
  int iBtSinGraph_Make_Width, iBtSinGraph_Make_Height;

  ExecutorService voTPool;
  CountDownLatch voCDLatch_Canvas;
  Future<Boolean> voFuture_Canvas;

  /**
   * Launch the application.
   */
  public static void main(String[] args) {
    // 以前はイベントもメイン・スレッドでしたが、
    // イベントはイベント・ディスパッチ・スレッドに分離されたために、
    // GUIコンポーネントの設定もイベント・ディスパッチ・スレッドで設定しなければならなくなったので、
    // メイン・スレッドでのGUIコンポーネントの設定はNGになりました、
    // 下記のように「EventQueue.invokeLater()」でイベント・ディスパッチ・スレッドに登録しなければなりません。
    EventQueue.invokeLater(new Runnable() {
      public void run() {
        try {
          oAppFrame = new SinGraph007();
          oAppFrame.setVisible(true);
        } catch (Exception ex) {
          ex.printStackTrace();
        }
      }
    });
  }

  /**
   * Create the frame.
   */
  public SinGraph007() {
    // 閉じるボタンをクリックされた場合の動作を設定
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    setTitle(sAppTitle);
    setLocation(50, 50);

    // ContentPaneの実態はJFrameにビルトインされているデフォルト・パネル。
    content = (JPanel) getContentPane();
    // content.setSize(500, 500);

    // content.setLayout(null);
    // getContentPane().add(oAppFrame, BorderLayout.CENTER);

    getContentPane().setLayout(null); // Layout 座標指定モード

    ccbSinGraph_WaveQnt = new JComboBox();
    ccbSinGraph_WaveQnt.setModel(new DefaultComboBoxModel(new Object[] { " 1 ", " 2 ", " 3 " }));
    ccbSinGraph_WaveQnt.setDoubleBuffered(false);
    ccbSinGraph_WaveQnt.setBorder(null);
    iCbSinGraph_WaveQnt_Width = ccbSinGraph_WaveQnt.getMinimumSize().width;
    iCbSinGraph_WaveQnt_Height = ccbSinGraph_WaveQnt.getMinimumSize().height;

    d1oCbSinGraph_ColorSets = new Color[] {
        Color.GREEN, Color.PINK,
        Color.RED, Color.YELLOW,
    };
    ccbSinGraph_Color = new JComboBox();
    ccbSinGraph_Color.setModel(new DefaultComboBoxModel(new Object[] { "グリーン", "ピンク", "赤", "黄色", }));
    ccbSinGraph_Color.setDoubleBuffered(false);
    ccbSinGraph_Color.setBorder(null);
    iCbSinGraph_Color_Width = ccbSinGraph_Color.getMinimumSize().width;
    iCbSinGraph_Color_Height = ccbSinGraph_Color.getMinimumSize().height;

    cbtSinGraph_Make = new JButton();
    cbtSinGraph_Make.setText("Make");
    iBtSinGraph_Make_Width = cbtSinGraph_Make.getMinimumSize().width;
    iBtSinGraph_Make_Height = cbtSinGraph_Make.getMinimumSize().height;
    cbtSinGraph_Make.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent ev) {
        if (null != oCanvas) {
          oCanvas.SinGraph_Make();
        }
      }
    });
    
    iCanvasWidth = 500;
    iCanvasHeight = 500;

    iLayoutX = 0;
    iLayoutY = 0;
    getContentPane().add(ccbSinGraph_WaveQnt);
    ccbSinGraph_WaveQnt.setBounds(iLayoutX, iLayoutY, iCbSinGraph_WaveQnt_Width, iCbSinGraph_WaveQnt_Height);

    iLayoutX = iLayoutX + iCbSinGraph_WaveQnt_Width; // iLayoutY = 0;
    getContentPane().add(ccbSinGraph_Color);
    ccbSinGraph_Color.setBounds(iLayoutX, iLayoutY, iCbSinGraph_Color_Width, iCbSinGraph_Color_Height);

    iLayoutX = iLayoutX + iCbSinGraph_Color_Width; // iLayoutY = 0;
    getContentPane().add(cbtSinGraph_Make);
    cbtSinGraph_Make.setBounds(iLayoutX, iLayoutY, iBtSinGraph_Make_Width, iBtSinGraph_Make_Height);

    iLayoutX = 0;
    iLayoutY = iLayoutY + iBtSinGraph_Make_Height;
    oCanvas = new CanvasObj(iLayoutX, iLayoutY, iCanvasWidth, iCanvasHeight);
    getContentPane().add(oCanvas);
    // oCanvas.setVisible(true);

    iLayoutX = iCanvasWidth;
    iLayoutY = iLayoutY + iCanvasHeight;
    content.setSize(iLayoutX, iLayoutY);

    // 「JFrame#setSize(~)」でフレーム・サイズを設定すると、
    // タイトルも含むウインドウ全体のサイズになります。
    // つまり、ウインドウ内の表示領域の縦がタイトルのサイズ分 少なくなります。
    // 「JFrame#getContentPane().setPreferredSize(~)」で設定し、
    // 「pack()」すれば、ContentPaneで設定された全表示領域が表示されます。
    content.setPreferredSize(content.getSize());
    pack();

    voTPool = Executors.newCachedThreadPool();
    voCDLatch_Canvas = new CountDownLatch(1);
    voFuture_Canvas = voTPool.submit(oCanvas);
    voTPool.shutdown();
    // ExecutorService#shutdownは既に投入済みの全タスクの
    // 処理が終わるまで待機してからスレッドを終了させます。
    // また、shutdownを実行しないと、mainスレッドが終了してもJVMは終了しません。
  }

  class SinGraph {
    CanvasObj oCanvas;
    // int iWidth, iHeight;
    int iMoveStride = 3;
    // volatile:最適化の抑制.
    volatile int iMoveDistance = 0;
    int iWaveQnt = 1;
    double vdWaveHeightRate = iWaveQnt;
    int iGraphXStep = 0;
    int iWaveWidth;
    int iWaveHeight;
    Color oColor = Color.BLUE;
    double vdRadian;
    double vdWaveWidth, vdWaveHeight;
    double vdGraphX1, vdGraphX2;
    double vdGraphY1, vdGraphY2;
    double vdWaveY1, vdWaveY2;
    double vdRate, vdRateInt;

    SinGraph(CanvasObj ccv, int iWQ, Color oC) {
      // コンストラクター自体には synchronized 修飾子を付与できないので、
      // synchronized ブロックで囲う。
      synchronized (this) {
        // iMoveDistance に対する競合(描画中の変更)を回避する。
        // 対象は SinGraph("自分")内の変数です。
        oCanvas = ccv;
        iWaveQnt = iWQ;
        vdWaveHeightRate = iWaveQnt; // sin グラフの高さの調整。
        oColor = oC;
      }
    }

    synchronized void Draw(Graphics oGraphic) {
      // iMoveDistance に対する競合(描画中の変更)を回避する。
      // 対象は SinGraph("自分")内の変数です。
      Graphics2D oGraphic2D = (Graphics2D) oGraphic;

      vdGraphX1 = -1;
      vdGraphX2 = -1;

      oGraphic2D.setColor(oColor);
      vdWaveWidth = (double) oCanvas.iWidth / iWaveQnt;
      vdWaveHeight = vdWaveWidth / (2 * Math.PI) * vdWaveHeightRate;
      iGraphXStep = 0;
      while (iGraphXStep < oCanvas.iWidth) { // true / false
        DrawBullet(oGraphic, iGraphXStep);
        iGraphXStep++;
      }
    }

    void DrawBullet(Graphics oGraphic, int iBulletGraphXStep) {
      Graphics2D oGraphic2D = (Graphics2D) oGraphic;

      oGraphic2D.setColor(oColor);

      if (0 == iBulletGraphXStep) {
        vdGraphX1 = -1;
        vdGraphX2 = -1;
      }
      vdWaveWidth = (double) oCanvas.iWidth / iWaveQnt;
      vdWaveHeight = vdWaveWidth / (2 * Math.PI) * vdWaveHeightRate;

      vdGraphX1 = vdGraphX2;
      vdGraphY1 = vdGraphY2;
      vdWaveY1 = vdWaveY2;
      vdRate = (double) (iBulletGraphXStep + oCanvas.iWidth - iMoveDistance) / oCanvas.iWidth * iWaveQnt;
      vdRateInt = Math.floor(vdRate);
      vdRate = vdRate - vdRateInt;
      vdGraphX2 = iBulletGraphXStep;
      vdRadian = 2 * Math.PI * vdRate;
      vdWaveY2 = Math.sin(vdRadian) * vdWaveHeight;
      vdGraphY2 = oCanvas.iHeight / 2 - vdWaveY2;
      if (0 <= vdGraphX1) {
        oGraphic2D.drawLine(
            (int) Math.round(vdGraphX1), (int) Math.round(vdGraphY1),
            (int) Math.round(vdGraphX2), (int) Math.round(vdGraphY2));
        // oCanvas.vdGraphX1 = oCanvas.vdGraphX1+vdGraphX1;
        // oCanvas.vdGraphX2 = oCanvas.vdGraphX2+vdGraphX2;
        oCanvas.vdWaveY1 = oCanvas.vdWaveY1 + vdWaveY1;
        oCanvas.vdWaveY2 = oCanvas.vdWaveY2 + vdWaveY2;
      }
    }
  }

  class CanvasObj extends JPanel implements Callable<Boolean> {
    // Swing には JCanvas は存在しないので、
    // グラフィックの描画には JPanel を継承して Canvas の代わりに使う。
    Thread oThread;
    Future<Boolean> voFuture_Canvas;
    // CountDownLatch voCDLatch_Alpha;
    // SinGraph oSinGraph;
    int iWidth;
    int iHeight;
    ArrayList<SinGraph> dl1oSinGraph = new ArrayList<SinGraph>();
    int iGraphXStep;
    double vdGraphX1, vdGraphX2;
    double vdGraphY1, vdGraphY2;
    double vdWaveY1, vdWaveY2;
    double vdWaveYRate = 0.666; // 合成波のY軸の倍率。

    CanvasObj(int x, int y, int w, int h) {
      super();
      setBounds(x, y, w, h);
      iWidth = getWidth();
      iHeight = getHeight();
      SinGraph_Make();

    }

    void SinGraph_Make() {
      dl1oSinGraph.add(new SinGraph(this,
          ccbSinGraph_WaveQnt.getSelectedIndex() + 1,
          d1oCbSinGraph_ColorSets[ccbSinGraph_Color.getSelectedIndex()]));
    }

    @Override
    public Boolean call() {
      while (true) { // true / false
        repaint();
        try {
          Thread.sleep(50); // ←50ミリ秒の sleep。
        } catch (InterruptedException ex) {
          // ex.printStackTrace();
          System.out.println("CanvasObj#(Boolean)call(): Interrupted Exception.");
          break;
        }
        synchronized (CanvasObj.this) {
          // SinGraph内の iMoveDistance変数に対する競合(描画中の変更)を回避する。
          // 対象は SinGraph内の変数なのだが、
          // (CanvasObj の) paint内のループ全体の処理を1つと見なす必要があるので
          // 実際の対象は CanvasObj とする必要がある。
          for (SinGraph oSinGraph : dl1oSinGraph.toArray(new SinGraph[0])) {
            // ↑この「new SinGraph[0]」の部分は要素がゼロ個の配列を指定しなければならないらしい。
            // それにより指定された型と同一の型が返されるらしい。
            oSinGraph.iMoveDistance = oSinGraph.iMoveDistance + oSinGraph.iMoveStride;
            if (iWidth <= oSinGraph.iMoveDistance) {
              oSinGraph.iMoveDistance = oSinGraph.iMoveDistance - iWidth;
            }
          }
        }
      }
      return null;
    }

    @Override
    public synchronized void paint(Graphics g) {
      Graphics2D g2 = (Graphics2D) g;
      // ↑(JPanel を継承しているので)ここの Graphics の実態は Graphics2D となるから、
      // キャストしてやれば Graphics2D が使える.

      g2.setBackground(Color.BLACK);
      g2.clearRect(0, 0, iWidth, iHeight);

      g2.setColor(Color.WHITE);
      g2.drawLine(0, iHeight / 2, iWidth, iHeight / 2);

      iGraphXStep = 0;
      vdGraphX1 = 0;
      vdGraphX2 = 0;
      while (iGraphXStep < iWidth) { // true / false
        vdWaveY1 = 0;
        vdWaveY2 = 0;
        vdGraphX1 = vdGraphX2;
        for (SinGraph oSinGraph : dl1oSinGraph.toArray(new SinGraph[0])) {
          // ↑この「new SinGraph[0]」の部分は要素がゼロ個の配列を指定しなければならないらしい。
          // それにより指定された型と同一の型が返されるらしい。
          oSinGraph.DrawBullet(g, iGraphXStep);
        }
        vdGraphX2 = iGraphXStep;
        if (2 <= dl1oSinGraph.size() && 0 < iGraphXStep) {
          vdGraphY1 = iHeight / 2 - vdWaveY1 * vdWaveYRate;
          vdGraphY2 = iHeight / 2 - vdWaveY2 * vdWaveYRate;
          g2.setColor(Color.WHITE);
          g2.drawLine(
              (int) Math.round(vdGraphX1), (int) Math.round(vdGraphY1),
              (int) Math.round(vdGraphX2), (int) Math.round(vdGraphY2));
        }
        iGraphXStep++;
      }
    }
  }
}

Block( Address 00000701 Identity 00000632 )






ページの表示順:{ 新しい順/ 古い順}.
初期・ページの表示・位置:{ 先頭ページ/ 末尾ページ}.
1ページ内のスレッド表示数:

   
   

管理者用 Password:

  




SMT Version 8.022(+A) Release M6.
Author : amanojaku.