プログラマメモ2

2009-02-25

[java]またキューして実行


Javaです。

またふただび、キューして実行。

以前も書いたけど、


どうも、wait,notify,が頭の中ですっきりしないので。
synchronizedされているところでしかwait,notifyできないです。
waitすると他のブロックされているスレッドが実行されます。

wait()はsynchronizedブロックの中で使用する。
wait()を呼び出すと、呼び出したスレッドはそこで実行を停止し、他のスレッドがsynchronizedの中に入って実行できる。
後から実行されたスレッドがnotify()を呼び出すと、そのスレッドがsynchronizedブロックから抜けた後にwait()を呼び出したスレッドが再実行される。Javaスレッドメモ(Hishidama's Java thread Memo)


上記の引用の通りですが、この「synchronizedブロックから抜けた後にwait()を呼び出したスレッドが再実行される」が理解できず、苦しみましたが、いまなら、なんとか頭でシュミレートできそうな気がします。

人に説明しろといわれたら、心もとないです。

またコード。
package th;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class TestEasyQue {

public static void main(String[] args) {

final Q q = new Q();
JFrame frame = new JFrame() {
{
JPanel panel = new JPanel() {
{
add(new JButton("start") {
{
addActionListener(new ActionListener() {
int i = 0;

@Override
public void actionPerformed(ActionEvent e) {
q.enqueue("addA " + i++);
q.enqueue(new Q.IExecutable() {
@Override
public void exec() {
try {
System.out
.println("*** >_<!! sleep!!");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}

}
});
}
});
}
});// end add
}
};

getContentPane().add(panel);
setSize(400, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
};

frame.setVisible(true);

}

static class Q {

LinkedList list = new LinkedList();
Thread worker = new Thread();

public Q() {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
synchronized (Q.this) {
while (!(0 < list.size())) {
try {
// System.out.println("i am wait...");
Q.this.wait();
} catch (Exception e) {
e.printStackTrace();
}
}//

}// synchronized

Object o = dequeue();

if (o instanceof IExecutable) {
exec((IExecutable) o);
continue;
}

System.out.println("*** " + o.toString());
}// while
}
}).start();
}

public synchronized void enqueue(Object o) {
list.addFirst(o);
notifyAll();
}

public synchronized Object dequeue() {
return list.removeLast();
}

void exec(IExecutable executable) {
try {
executable.exec();
} catch (Exception e) {
e.printStackTrace();
} catch (Throwable e) {
e.printStackTrace();
}
}

interface IExecutable {
public void exec();
}
}
}




[シェル] -z 文字列の長さがあるかないかです。


シェルです。

文字列の長さがあるかないかです。
-zで聞けるようです。

えーと、シェルは全然おぼえていないです。毎回、Webで検索してます。
いろいろあるシェルの区別がついてないのもの悲しい
Orz...


#!/bin/bash

a="";

if [ -z $a ]
then
echo "zero";
else
echo "not zero";
fi


参考




2009-02-23

[java]ロックしないと怒ります。


Javaです。

いまだによく理解できないものに同期処理があります。

まずは、synchronized処理から。
単純にふたつのスレッドから、StringBuilderに連続して文字を書き込みたいということを想定してみます。
ひとつが完全に処理を終わらないと、片一方は処理してはいけないという仕様です。
synchronizedブロックを使って実現してみます。
もちろん、両方でsynchronizedブロックを使わないとてんでばらばらな書き込みになってしまいます。

package th;

public class TestA {

public static void main(String[] args) throws InterruptedException {

final StringBuilder builder = new StringBuilder();

Thread thread = new Thread(new Runnable() {
public void run() {
synchronized (builder) {
for (int i = 0; i < 100; i++) {
builder.append("A" + i).append("\n");
sleep(10);
}
}
}
});

Thread thread2 = new Thread(new Runnable() {
public void run() {
synchronized (builder) {
for (int i = 0; i < 100; i++) {
builder.append("B" + i).append("\n");
sleep(10);
}
}
}
});

thread.start();
thread2.start();

thread.join();
thread2.join();
System.out.println(builder);
}

static void sleep(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

static class A {
StringBuilder builder = new StringBuilder();
}

}


つぎに、Javaの標準パッケージにあるjava.util.concurrent.locks.Lockを使ってみます。
下のような使い方をしてみました。

package th;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TestB {

public static void main(String[] args) throws InterruptedException {

class Writer {
final StringBuilder builder = new StringBuilder();
final Lock lock = new ReentrantLock();

void lock() {
this.lock.lock();
}

void unlock() {
this.lock.unlock();
}

void writer(String s) {
builder.append(s);
}

public String toString() {
return builder.toString();
}
}

final Writer writer = new Writer();

Thread thread = new Thread(new Runnable() {
public void run() {
writer.lock();
try {
for (int i = 0; i < 100; i++) {
writer.writer("A" + i + "\n");
sleep(10);
}
} finally {
writer.unlock();
}

}
});

Thread thread2 = new Thread(new Runnable() {
public void run() {
writer.lock();
try {
for (int i = 0; i < 100; i++) {
writer.writer("B" + i + "\n");
sleep(10);
}
} finally {
writer.unlock();
}
}
});

thread.start();
thread2.start();

thread.join();
thread2.join();
System.out.println(writer);
}

static void sleep(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

static class A {
StringBuilder builder = new StringBuilder();
}

}


lockとunlockの組み合わせがsynchronizedブロックよりわかりやすいかなと、個人的には思います。

ただ、lockをしないで使うと、やはりばらばらな書き込みができてしまいます。

次に、lockしないと怒られる(実行時エラーを吐く)というふうにしてみます。
標準パッケージにjava.util.concurrent.locks.ReentrantLockというのがありまして、このクラスは、isHeldByCurrentThreadメソッドを持ちます。

使われるときにisHeldByCurrentThreadで現在のスレッドが、lockしてない場合は、例外を吐くというふうにしています。

package th;

import java.util.concurrent.locks.ReentrantLock;

public class TestC {

public static void main(String[] args) throws InterruptedException {

class Writer {
final StringBuilder builder = new StringBuilder();
final ReentrantLock lock = new ReentrantLock();

void lock() {
this.lock.lock();
}

void unlock() {
this.lock.unlock();
}

void writer(String s) {
if (!lock.isHeldByCurrentThread()) {
throw new RuntimeException("***");
}

builder.append(s);
}

public String toString() {
return builder.toString();
}
}

final Writer writer = new Writer();

Thread thread = new Thread(new Runnable() {
public void run() {
writer.lock();
try {
for (int i = 0; i < 100; i++) {
writer.writer("A" + i + "\n");
sleep(10);
}
} finally {
writer.unlock();
}

}
});

Thread thread2 = new Thread(new Runnable() {
public void run() {
// writer.lock();
/*
* lockしてないので実行時エラーがでます。
*/
try {
for (int i = 0; i < 100; i++) {
writer.writer("B" + i + "\n");
sleep(10);
}
} finally {
// writer.unlock();
}
}
});

thread.start();
thread2.start();

thread.join();
thread2.join();
System.out.println(writer);
}

static void sleep(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

static class A {
StringBuilder builder = new StringBuilder();
}

}



最後にsynchronizedブロックで似たようなことを実現してみます。

現在のスレッドがこのロックを保持しているかどうかを照会するにはThread.holdsLock(java.lang.Object) メソッドを使います。

下記のようなコードにしてみました。

package th;

public class TestD {

public static void main(String[] args) throws InterruptedException {

class Writer {
final StringBuilder builder = new StringBuilder();

void writer(String s) {
if (!Thread.holdsLock(this)) {
throw new RuntimeException("***");
}
builder.append(s);
}

public String toString() {
return builder.toString();
}
}

final Writer writer = new Writer();

Thread thread = new Thread(new Runnable() {
public void run() {

synchronized (writer) {
for (int i = 0; i < 100; i++) {
writer.writer("A" + i + "\n");
sleep(10);
}
}
}
});

Thread thread2 = new Thread(new Runnable() {
public void run() {

/*
* writerをsynchronizedしていないので例外が発生します。
*/
for (int i = 0; i < 100; i++) {
writer.writer("B" + i + "\n");
sleep(10);
}

}
});

thread.start();
thread2.start();

thread.join();
thread2.join();
System.out.println(writer);
}

static void sleep(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

static class A {
StringBuilder builder = new StringBuilder();
}

}




2009-02-20

ボイラープレート - boilerplate


boilerplate
ボイラープレートとは、《お決まりのソースコード断片》とかそんな意味のようです。

辞書的には、「鋳型、共通記事、決まり文句」とかいう意味。

コーディングでは、ちょっとマイナスイメージなにおいがしますね。
手で書かず、ツールで補完しろとか。
繰り返しあわられるものを毎回書くのは、どうもねー。

参考




2009-02-19

[java][用語]シグネチャ


Javaです。用語です。Signature(シグネチャ)。
いわれて気がつかなかったので、メモ。
えーと、Javaでシグネチャというと、メソッド名、引数の個数、各引数の型の組み合わせってこと。
用語って大切だねーということで。

で、僕ぐらいの年齢になるとまあ、年の功ってことで、いろいろ知ってる気になってますが、
はじめ、同じ名前で複数のメソッドをもつことをさしてるのかなぁと思って、ポリモーフィズム - Wikipediaだっけ?とか一瞬思ったんですけど。思い出したかったのはシグネチャのことでした。




2009-02-10

[java]組み合わせ


組み合わせを出力したかったので、ためしてみた。
データ構造としてスタックって重要なんだなぁと。

結果

[T, 0, A]
[T, 0, B]
[T, 1, A]
[T, 1, B]
[F, 0, A]
[F, 0, B]
[F, 1, A]
[F, 1, B]


コード
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class TestFlag2 {

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

/**
* お手軽スタック
*
* @author nakawaka
*
*/
static class Stack {

Object[] objects;
int pos = 0;

public Stack(int depth) {
this.objects = new Object[depth];
}

public void push(Object o) {
objects[pos++] = o;
}

public Object pop() {
return objects[--pos];
}

public Object[] toArray(){
Object[] dest = new Object[pos];
System.arraycopy(objects, 0, dest, 0, pos);
return dest;
}
}

static void b() {

List list1 = Arrays.asList(new String[] { "T", "F"});
List list2 = Arrays.asList(new String[] { "0", "1" });
List list3 = Arrays.asList(new String[] { "A", "B" });
List list4 = Arrays.asList(new String[] { "W", "X", "Y", "Z" });

List result = comb(list1, list2, list3);

for (Object o : result) {
System.out.println(o);
}
}

/**
* <p>
* 組み合わせます。
* </p>
*
* @param lists
* @return
*/
static List<String> comb(List<String>... lists) {
List result = new ArrayList();
comb(lists, /* はじめは0スタートで */0, new Stack(lists.length), result);
return result;
}

static void comb(List[] lists, int pos, Stack stack,
List result) {

if (!(pos < lists.length))
return;

List list = lists[pos];
for (Object s : list) {
stack.push(s);
comb(lists, /* 一つ進める */pos + 1, stack, result);
// 尻尾なら結果として登録
if (pos == lists.length - 1) {
// System.out.println(stack);
result.add(Arrays.asList(stack.toArray()));
}
stack.pop();
}
return;
}
}




[java]0埋めね。


Javaです。
毎回忘れるには理由があるわけです。

0埋めね。
Javadocには下記のようにあります。


一般、文字、および数値型の書式指示子では、次の構文が使用されます。

%[argument_index$][flags][width][.precision]conversion


使うのは[flags][width]conversion

0埋めなので、flagsは0
二桁までにしたいので、widthは2
整数値なので、conversionはd

System.out.printf("%02d%n", 0);
System.out.printf("%02d%n", 1);
System.out.printf("%02d%n", 57);
System.out.printf("%02d%n", 100);




2009-02-09

[java]JTreeで、ノードハンドルのクリックのみで、ノードを開くようにする方法


Javaです。swingです。JTreeです。

同僚の方が、ノードハンドルのクリックのみで、ノードを開く実装を考えていたので、それをヒントに、僕も実装してみました。
イベントは、mousePressed、treeWillExpand、を使います。そしてフラグを用意します。
ちょっといけてない感じがしますが。。。

余談:
別のアプローチとして、BasicTreeUIをごにょごにょすればできますね。
BasicTreeUIはHandlerという内部クラスをもっていましてその、handleSelectionメソッドに、checkForClickInExpandControl、selectPathForEventに対しての呼び出し部分があります。

ここの処理はTreeUIを自前で用意しないとちょっと処理を変更できないかなぁ。

package jtree.a;

import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeWillExpandListener;
import javax.swing.tree.ExpandVetoException;
import javax.swing.tree.TreePath;

public class TestMain {

public static void main(String[] args) {

MyFrame myFrame = new MyFrame();
myFrame.setVisible(true);
}

}

class MyFrame extends JFrame {

private static final long serialVersionUID = 1L;
{

setSize(300, 200);
setLocation(300, 500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setAlwaysOnTop(true);
getContentPane().add(new JPanel() {

private static final long serialVersionUID = 1L;

{
add(new JTree() {

private static final long serialVersionUID = 1L;

{
setPreferredSize(new Dimension(300,200));
/*
* イベントの発生順序が、 ノードハンドルの場合(TreeExpansionEvent,
* MouseEvent[MOUSE_PRESSED])
* ノードの場合(MouseEvent[MOUSE_PRESSED], TreeExpansionEvent,
* MouseEvent[MOUSE_PRESSED])
* なので、最終的にmousePressedで、開くようにする。
*/
class MyMouseAndTreee extends MouseAdapter implements
TreeWillExpandListener {

boolean canOpen = false;
TreePath willExpand;

@Override
public void mousePressed(MouseEvent e) {
System.err.println("" + e);
if (willExpand == null)
return;

/*
* マウスがプレスされたロケーションで取得されたパス
*/
TreePath path = getPathForLocation(e.getX(), e
.getY());
System.out.println("*** =>" + path);
try {

/*
* マウスプレスで取得された。位置でTreePathが取得できるか。
*/
if (path == null) {
canOpen = true;// 開くフラグ
expandPath(willExpand);
return;
}

} finally {
willExpand = null;
}

}

@Override
public void treeWillCollapse(TreeExpansionEvent e)
throws ExpandVetoException {
}

@Override
public void treeWillExpand(TreeExpansionEvent e)
throws ExpandVetoException {

System.err.println("" + e);

if (canOpen) {
canOpen = false;
return;
}

willExpand = e.getPath();
throw new ExpandVetoException(e);// 例外で開かない
}

}
MyMouseAndTreee treee = new MyMouseAndTreee();
addMouseListener(treee);
addTreeWillExpandListener(treee);
}

});// end add
}
});// end add
}
}




2009-02-06

[java]スレッドのjoin


Javaです。スレッドのjoinは、スレッドが終了するまで待機します。

で、このスレッドが終了というのが正直よくわかってないです。

なので、簡単なサンプル
どうかな。。。

package th;

public class TestJoin {

public static void main(String[] args) {

new Thread(new Runnable() {

@Override
public void run() {
Thread thread = new Thread(new Runnable() {

@Override
public void run() {
sleep(2000);
System.out.println("wake up!!!");
}
});
System.out.println("*** GO!!");
thread.start();
// 待機時間をしていできるよ。
join(thread, 1000);
System.out.println("*** GO GO!!");
}
}) {

}.start();

}

public static void sleep(long t) {
try {
System.out.println("i am sleep... " + t + "ms");
Thread.sleep(t);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

public static void join(Thread th, long t) {
try {
th.join(t);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}




2009-02-04

[java]ドラッグして動かせるパネル




swingxのDropShadowBorderをためしてみました。
あわせて、ドラッグして動かせるパネルです。
パネルにイメージファイルをドロップできるようにしてみました。

コンポーネントを置くコンテナのレイアウトマネジャーをnullにすると簡単に実現できますね。
コンポーネントを置けるとコンポーネントにいろいろリスナーを設定したり効果をつけやすいので、重宝するかも。


import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Point;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.IOException;
import java.util.List;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.TransferHandler;

import org.jdesktop.swingx.JXPanel;
import org.jdesktop.swingx.border.DropShadowBorder;

public class Test_drop_shadow_border {

static JXPanel createDragablleJPanel() {
return new JXPanel() {

@Override
protected void paintComponent(Graphics g) {
if (image != null) {
Insets insets = getBorder().getBorderInsets(this);

g.drawImage(image, insets.top, insets.left, getWidth()
- (insets.left + insets.right), getHeight()
- (insets.top + insets.bottom), null);
g.setColor(Color.WHITE);
g.drawRect(insets.top, insets.left, getWidth()
- (insets.left + insets.right), getHeight()
- (insets.top + insets.bottom));
}
super.paintComponent(g);
}

{
setOpaque(false);
setPreferredSize(new Dimension((int)(200*1.33), 200));
setSize(new Dimension((int)(200*1.33), 200));
DropShadowBorder border = new DropShadowBorder(Color.DARK_GRAY,
20, .2f, 12, false, false, true, true);
setLocation(100, 10);
setBorder(border);

setTransferHandler(new TransferHandler() {
@Override
public boolean importData(TransferSupport support) {
DataFlavor[] dataFlavors = support.getDataFlavors();

for (DataFlavor dataFlavor : dataFlavors) {
// System.out.println(dataFlavor);
// System.out.println(dataFlavor
// .getDefaultRepresentationClass());

if (dataFlavor.isFlavorJavaFileListType()) {

Object object;
try {
object = support.getTransferable()
.getTransferData(dataFlavor);
List list = (List) object;
for (Object o : list) {
if (o instanceof File) {
image = ImageIO.read((File) o);
repaint();
break;
}
}
// System.out.println(object.getClass());

} catch (UnsupportedFlavorException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

}
}
return true;
}

@Override
public boolean canImport(TransferSupport support) {
return true;
}

});
addMouseMotionListener(new MouseAdapter() {

{
addMouseListener(this);
}
Point origin = null;

boolean isPressed = false;

@Override
public void mouseReleased(MouseEvent e) {
isPressed = false;
origin = null;
}

@Override
public void mousePressed(MouseEvent e) {
isPressed = true;
origin = e.getPoint();
}

@Override
public void mouseDragged(MouseEvent e) {
// System.out.println(e);
if (!isPressed)
return;
Point nowPoint = e.getPoint();
int dx = nowPoint.x - origin.x;
int dy = nowPoint.y - origin.y;
setLocation(getX() + dx, getY() + dy);
}

});//

}

Image image;

};// return end...
}

public static void main(String[] args) {

JFrame frame = new JFrame() {
{
getContentPane().add(new JPanel() {
{
setLayout(null);
setBackground(Color.LIGHT_GRAY);
setPreferredSize(new Dimension(200, 200));

add(createDragablleJPanel());
add(createDragablleJPanel());
add(createDragablleJPanel());
add(createDragablleJPanel());
add(createDragablleJPanel());
add(createDragablleJPanel());
add(createDragablleJPanel());
add(createDragablleJPanel());
add(createDragablleJPanel());
}

});
}
};
frame.setSize(300, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setAlwaysOnTop(true);
frame.setVisible(true);
}

}




[java]局所的にクラスをオーバーライドして、返すファクトリーメソッドを考えてみた。


Javaです。

局所的にクラスをオーバーライドして、返すファクトリーメソッドを考えてみました。
ここで例にしてみたのはswingコンポーネントです。

特定のクラスの処理だけをオーバーライドして返すファクトリーメソッドです。
ジェネリックーを意識してますけど、どうでしょう。

import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class NewInstance {
public static void main(String[] args) throws InstantiationException,
IllegalAccessException {
JTextField textField = CREATE(JTextField.class);
System.out.println(textField.getText());
}

/**
* <p>
* 局所的にクラスをオーバーライドして、返すファクトリーメソッドを考えてみた。
* </p>
* @param <T>
* @param clazz
* @return
* @throws InstantiationException
* @throws IllegalAccessException
*/
static public <T extends JComponent> T CREATE(Class<T> clazz)
throws InstantiationException, IllegalAccessException {

class A extends JTextArea {
public void method() {
System.out.println("*** HOGEGEO");
}
}

class B extends JComboBox {
public void method() {
System.out.println("*** HOGEGEO");
}
}

class C extends JTextField {
public String getText() {
return "**** OK";
}
}

if (JTextArea.class.isAssignableFrom(clazz)) {
return clazz.cast(new A());
}
if (JComboBox.class.isAssignableFrom(clazz)) {
return clazz.cast(new B());
}
if (JTextField.class.isAssignableFrom(clazz)) {
return clazz.cast(new C());
}
return clazz.newInstance();
}

}




2009-02-03

[java]例外を使ってメソッドがよばれた位置を表示


メソッドがどういうふうに呼ばれたか知りたい場合に、例外を発生させてスタックトレースを調べるという方法、かなり昔からあるテクニック。

デバッガ使えばいいんだろうけど。

package debug;

public abstract class DebugUtils {

public static final String trace() {
String trace = "";
try {
alwaysOcurringException();
} catch (Exception e) {
StackTraceElement[] stackTraceElements = e.getStackTrace();
StringBuilder buffer = new StringBuilder();
StringBuilder padding = new StringBuilder();
final String PAD = " ";
for (StackTraceElement stackTraceElement : stackTraceElements) {
if (!eq(stackTraceElement.getMethodName(),
"alwaysOcurringException")
&& !eq(stackTraceElement.getMethodName(), "trace")) {
buffer.append(padding).append(stackTraceElement).append(
"\n");
padding.append(PAD);
}
}

trace = new String(buffer);
}
return trace;
}

static protected final void alwaysOcurringException() throws Exception {
throw new FakeException();
}

static class FakeException extends Exception {
private static final long serialVersionUID = 1L;
}

protected static boolean eq(Object object, Object object2) {
return object == null ? object2 == null : object.equals(object2);
}

}


僕の場合、デバッガ使うとどうしても頭のドライブ感とマッチしないときがあって、ついつい標準出力させてちゃうんだよね。
人それぞれということで。




 

プログラマの本棚