posts - 2,comments - 7,trackbacks - 0

Core Java™ 2: Volume II–Advanced Features读书笔记

 

Chapter 1:  MultiThreading

 

 线程和进程的区别:The essential difference is that while each process has a complete set of its own variables, threads share the same data

 简单地说,一个进程是资源分配的最小单位, 线程是程序运行的最小单位。

 

 多线程的好处:可以分时的让程序执行不同的任务,例如服务器程序

               GUI环境,如果有一个耗时的任务,不需要阻塞其他的任务。

 

 Java 创建线程的两种方式

 

1.       extends Thread

2.       implements Runnable

 

 在第一种方式下:

 

  Class MyThread extends Thread {

      //程序执行的内容

Public void run() {

     

}

}

  使用方式

     Thread th=new MyThread();

     th.start();

 

 第二种方式下:

   Class Worker implements Runnable {

       Public void run() {

       }

    }

    Thread th=new Thread(Worker);

    Th.start();

 

  有时候为了方便,也可以如此,内部类实现而已。

   Thread th=new Thread ( new Runnable() {

          Public void run()

          {

                    }

        );

 

2 中止线程

既然启动了线程,自然有时候需要中止,java提供一个stop()的方法。但这是一个deprecated的方法,可以使用interrupt()方法。 建议使用方法如下:

 

    Public void run() {

         While(!isInterrupted()) {

         }

     }

 

线程的几种状态:

 

 

 

一个线程在运行状态如果碰到中断或者等待资源或者是sleep就进入block状态,只有条件满足的时候才进入Runnable状态。

 

1.   If a thread has been put to sleep, the specified number of milliseconds must expire.

2.   If a thread is waiting for the completion of an input or output operation, then the operation must have finished.

3.   If a thread called wait, then another thread must call notifyAll or notify. (We cover the wait and notifyAll/notify methods later in this chapter.)

4.   If a thread is waiting for an object lock that was owned by another thread, then the other thread must relinquish ownership of the lock. (You will see the details later in this chapter.)

5.    If a thread has been suspended, then someone must call its resume method. However, since the suspend method has been deprecated, the resume method has been deprecated as well, and you should not call it in your own code.

 

可以用isAlive()来判断一个线程是否停止。 注意一点,一个线程如果停止了,就不能再被重新启动了。也就是说:

     Thread a =new Thread(Runnable);

a.    start();

a.    interrupt();

a.    start()这时候不能重新启动了。呵呵

Daemon线程

 setDaemon(true);

这种线程比较特殊,如果系统只有Daemon线程,程序就会推出,典型的是Timer类的线程。

ThreadGroup线程组

 线程可以分类统一管理。

Thread Priority优先级

setPriority 可以设置。

You can set the priority to any value between MIN_PRIORITY (defined as 1 in the Thread class) and MAX_PRIORITY (defined as 10). NORM_PRIORITY is defined as 5.

·         static void yield()

causes the currently executing thread to yield. If there are other runnable threads whose priority is at least as high as the priority of this thread, they will be scheduled next. Note that this is a static method

什么叫做自私线程Selfish Threads

  就是说一个线程,用一个while或者for循环,不停的跑,也不sleep,其他线程就没机会调度到了。

 when a thread contains a tight loop, a loop in which it carries out a lot of work without giving other threads a chance

例如:

  for (int i = 1; i <= 1000; i++)
         {
            b.move();
            if (selfish)
            {
               // busy wait for 5 milliseconds
               long t = System.currentTimeMillis();
               while (System.currentTimeMillis() < t + 5)
                  ;
            }
            else
               sleep(5);
         }

如果selfish变量为true了,就不sleep了,不停的跑。。。 这种情况工作中也碰到过,就是一个线程while循环了,其他线程就调度不到了。改变优先级都没有用。

 

线程同步:Synchronized

 很简单的,当需要访问共享的资源的时候,就需要Synchronized. 这个就是一把锁,保证只有一个线程能访问。

插入:

 The volatile keyword is designed to address these situations. Loads and stores of a 64-bit variable that is declared as volatile are guaranteed to be atomic

Wait() notify() notifyAll() 方法

注意这几个方法都是Object的方法, 不是Thread的方法, Wait()方法是中止当前线程执行,

进入Blocked状态,notify()方法,是通知其他线程可以进入,一般使用notifyAll()让线程调度程序自动选择blocked的线程进入Runnable状态。

 

 

同步的几种: 

 Synchronized Method 只有一个线程可以进入该方法。

 Synchronized Object : 该对象上的所有同步方法都不能执行

   例如:

      public void run()
{
   . . .
   synchronized (bank) // lock the bank object
   {
      if (bank.getBalance(from) >= amount)
         bank.transfer(from, to, amount);
   }
   . . .
}

In this sample code segment, the synchronized block will run to completion before any other thread can call a synchronized method on the bank object.

 

Synchronized Static Methods

 

 考虑Singleton 模式

 

 public class Singleton
{
   public static Singleton getInstance()
   {
      if (instance == null)
         instance = new Singleton(. . .);
      return instance;
   }
 
   private Singleton(. . .) { . . . }
   . . .
   private static Singleton instance;
}

这本身是不安全的,当一个instance产生,这时候又产生一个instance,所以需要

同步

        public static synchronized Singleton getInstance()
{
   if (instance == null)
      instance = new Singleton(. . .);
   return instance;
}

 

Calling a static method locks the class object Singleton.class ,当调用static的同步方法的时候,就需要锁定class对象

 

Therefore, if one thread calls a synchronized static method of a class, all synchronized static methods of the class are blocked until the first call returns.

 

 

DeadLocks Starving 死锁和饥饿

 

死锁就是说每个线程都有部分资源,但需要别的资源。

例如A1000 块,想转账2000B

    B1000快,想转2000A

 其实任何人都转不了。。。。但只要一个人开始工作,就开始转了。。。

 

饥饿就是有的线程太狠了,不释放,别的线程没有被调度的机会。。

 

GUI中的线程

 

 这里有一个需要注意的地方,因为GUI本身有一个事件处理dispatcher线程,你要处理和GUI相关的操作,一定要

   SwingUtils.invokeLater(Thread);

 

The last rule is often called the single thread rule for Swing programming. There are a few exceptions to the single thread rule.

1.    A few Swing methods are thread safe. They are specially marked in the API documentation with the sentence "This method is thread safe, although most Swing methods are not." The most useful among these thread-safe methods are:

2.           JTextComponent.setText
3.           JTextArea.insert
4.           JTextArea.append
5.           JTextArea.replaceRange

6.    The following methods of the JComponent class can be called from any thread:

7.           repaint
8.           revalidate

The repaint method schedules a repaint event. You use the revalidate method if the contents of a component have changed and the size and position of the component must be updated. The revalidate method marks the component's layout as invalid and schedules a layout event. (Just like paint events, layout events are coalesced. If there are multiple layout events in the event queue, the layout is only recomputed once.)

Runnable updater = new LabelUpdater(label, percentage);
EventQueue.invokeLater(updater);

The invokeLater method returns immediately when the event is posted to the event queue. The run method is executed asynchronously. The invokeAndWait method waits until the run method has actually been executed.

这里最好使用SwingUtils的方法。。

 

 

Timers

  这玩艺就是一个包装线程的计数器

 

Timer t = new Timer(1000, listener);

Call

t.start();

to start the timer. Then, the actionPerformed method of the listener class is called whenever a timer interval has elapsed. The actionPerformed method is automatically called on the event dispatch thread, not the timer thread, so that you can freely invoke Swing methods in the callback.

To stop the timer, call

t.stop();

 

什么时候使用线程

  ProgressBar应该使用线程。。。

 

 

最后是一个和solaris pipe很类似的IPC通信方式

 

Using Pipes for Communication Between Threads

Sometimes, the communication pattern between threads is very simple. A producer thread generates a stream of bytes. A consumer thread reads and processes that byte stream. If no bytes are available for reading, the consumer thread blocks. If the producer generates data much more quickly than the consumer can handle it, then the write operation of the producer thread blocks. The Java programming language has a convenient set of classes, PipedInputStream and PipedOutputStream, to implement this communication pattern. (There is another pair of classes, PipedReader and PipedWriter, if the producer thread generates a stream of Unicode characters instead of bytes.)

The principal reason to use pipes is to keep each thread simple. The producer thread simply sends its results to a stream and forgets about them. The consumer simply reads the data from a stream, without having to care where it comes from. By using pipes, you can connect multiple threads with each other without worrying about thread synchronization.

Example 1-13 is a program that shows off piped streams. We have a producer thread that emits random numbers at random times, a filter thread that reads the input numbers and continuously computes the average of the data, and a consumer thread that prints out the answers. (You'll need to use CTRL+C to stop this program.) Figure 1-18 shows the threads and the pipes that connect them. UNIX users will recognize these pipe streams as the equivalent of pipes connecting processes in UNIX.

Figure 1-18. A sequence of pipes

Piped streams are only appropriate if the communication between the threads is on a low level, such as a sequence of numbers as in this example. In other situations, you can use queues. The producing thread inserts objects into the queue, and the consuming thread removes them.

Example 1-13 PipeTest.java
  1. import java.util.*;
  2. import java.io.*;
  3.
  4. /**
  5.    This program demonstrates how multiple threads communicate
  6.    through pipes.
  7. */
  8. public class PipeTest
  9. {
 10.    public static void main(String args[])
 11.    {
 12.       try
 13.       {
 14.          /* set up pipes */
 15.          PipedOutputStream pout1 = new PipedOutputStream();
 16.          PipedInputStream pin1 = new PipedInputStream(pout1);
 17.
 18.          PipedOutputStream pout2 = new PipedOutputStream();
 19.          PipedInputStream pin2 = new PipedInputStream(pout2);
 20.
 21.          /* construct threads */
 22.
 23.          Producer prod = new Producer(pout1);
 24.          Filter filt = new Filter(pin1, pout2);
 25.          Consumer cons = new Consumer(pin2);
 26.
 27.          /* start threads */
 28.
 29.          prod.start();
 30.          filt.start();
 31.          cons.start();
 32.       }
 33.       catch (IOException e){}
 34.    }
 35. }
 36.
 37. /**
 38.    A thread that writes random numbers to an output stream.
 39. */
 40. class Producer extends Thread
 41. {
 42.    /**
 43.       Constructs a producer thread.
 44.       @param os the output stream
 45.    */
 46.    public Producer(OutputStream os)
 47.    {
 48.       out = new DataOutputStream(os);
 49.    }
 50.
 51.    public void run()
 52.    {
 53.       while (true)
 54.       {
 55.          try
 56.          {
 57.             double num = rand.nextDouble();
 58.             out.writeDouble(num);
 59.             out.flush();
 60.             sleep(Math.abs(rand.nextInt() % 1000));
 61.          }
 62.          catch(Exception e)
 63.          {
 64.             System.out.println("Error: " + e);
 65.          }
 66.       }
 67.    }
 68.
 69.    private DataOutputStream out;
 70.    private Random rand = new Random();
 71. }
 72.
 73. /**
 74.    A thread that reads numbers from a stream and writes their
 75.    average to an output stream.
 76. */
 77. class Filter extends Thread
 78. {
 79.    /**
 80.       Constructs a filter thread.
 81.       @param is the output stream
 82.       @param os the output stream
 83.    */
 84.    public Filter(InputStream is, OutputStream os)
 85.    {
 86.       in = new DataInputStream(is);
 87.       out = new DataOutputStream(os);
 88.    }
 89.
 90.    public void run()
 91.    {
 92.       for (;;)
 93.       {
 94.          try
 95.          {
 96.             double x = in.readDouble();
 97.             total += x;
 98.             count++;
 99.             if (count != 0) out.writeDouble(total / count);
100.          }
101.          catch(IOException e)
102.          {
103.             System.out.println("Error: " + e);
104.          }
105.       }
106.    }
107.
108.    private DataInputStream in;
109.    private DataOutputStream out;
110.    private double total = 0;
111.    private int count = 0;
112. }
113.
114. /**
115.    A thread that reads numbers from a stream and
116.    prints out those that deviate from previous inputs
117.    by a threshold value.
118. */
119. class Consumer extends Thread
120. {
121.    /**
122.       Constructs a consumer thread.
123.       @param is the input stream
124.    */
125.    public Consumer(InputStream is)
126.    {
127.       in = new DataInputStream(is);
128.    }
129.
130.    public void run()
131.    {
132.       for(;;)
133.       {
134.          try
135.          {
136.             double x = in.readDouble();
137.             if (Math.abs(x - oldx) > THRESHOLD)
138.             {
139.                System.out.println(x);
140.                oldx = x;
141.             }
142.          }
143.          catch(IOException e)
144.          {
145.             System.out.println("Error: " + e);
146.          }
147.       }
148.    }
149.
150.    private double oldx = 0;
151.    private DataInputStream in;
152.    private static final double THRESHOLD = 0.01;

 

 

建议: 实现一个多线程的生产者,消费者模型。

posted on 2005-04-15 23:05 潇湘才子杨的博客 阅读(683) 评论(0)  编辑  收藏 所属分类: J2SE

只有注册用户登录后才能发表评论。


网站导航: