驯服Java线程(一)

原创 2003年03月05日 09:03:00

JAVA 线程架构<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

Java 多线程编程其实并不象大多数的书描述的那样简单,所有关于UI(用户界面)的Java编程都要涉及多线程。这一章将会通过讨论几种操作系统的线程架构和这些架构将会怎样影响Java多线程编程。按照这样思路,我将介绍一些在Java的入门级书籍中描述的不慎清楚的关键术语和概念。理解这些概念是使你能够看懂本书所提供的例子的必备条件。

 

多线程编程的问题

象鸵鸟一样的把自己的头埋在沙子里,假装不去考虑多线程的问题其实是目前很多人进行Java编程共同弊病。但是在真正的产品中,你却无法回避这个严重的问题。目前,市面上大多数的书对Java线程的描述都是很肤浅的,甚至它们提供的例子本身就无法在多线程的环境下正确运行。

事实上,多线程是影响所有代码的重要因素。可以极端一点的说,单线程的代码在现实应用中,一钱不值,甚至根本无法运行,更不用说正确性和高效率了。所以你应该从一开始就把多线程作为一个重要的方面,融入你的代码架构。

 

所有不平凡的Java程序都是多线程的

不管你喜欢与否,所有的Java程序除了小部分非常简单的控制台程序都是基于多线程的。原因在于JavaAbstract Windowing Toolkit ( AWT )和它的扩展SwingAWT用一个特殊的线程处理所有的操作系统级的事件,这个特殊的线程是在第一个窗口出现的时候产生的。因此,几乎所有的AWT程序都有至少2个线程在运行:一个是main函数所在的线程和处理来自OS的事件和调用注册的监听者的响应方法(也就是回调函数)的AWT线程。必须注意的是所有注册的监听者方法,运行在AWT线程上,而不是人们一般认为的main函数(这也是监听器注册的线程)。

这种架构有两个问题。第一,虽然监听器的方法是运行在AWT线程上的,但是他们其实都是在main线程上声明的内部类(inner-class)。第二,虽然监听器的方法是运行在AWT线程上的,但是它一般会非常频繁的访问它的外部类,也就是运行在main线程上的类的成员变量。当这两个线程竞争(compete)访问同一个对象实例(Object)时,会引起非常严重的线程同步问题。适当的使用关键字synchronized是保证两个线程安全访问共享对象的必要手段。

更糟的是,AWT线程不但止处理监听器方法,还有响应来自操作系统的事件。这就意味着,如果你的监听器方法占用大量的CPU时间来进行处理,则你的程序将无法响应操作系统级的事件(例如鼠标点击事件和键盘事件)。这些事件将会被阻塞在事件队列中,直到监听器方法返回。具体的表现就是UI的死锁。这样会让用户无法接受的。Listing 1.1就是这样一个无响应UI的例子。程序产生一个包含两个按钮的FrameSleep按钮使它所在的线程(也就是前面所说的AWT事件处理线程)休眠5秒钟。Hello按钮只是简单的在控制台上打印“Hello World”。在你按下Sleep按钮5秒钟之内,无论你按多少次Hello按钮,程序都不会有任何响应。如果你在这期间按下了Hello按钮5次。那么“Hello World”将会立即被连续打印五次,当你Sleep按钮的监听器方法结束以后。这就证明了5个鼠标点击事件被阻塞在事件队列里,直到Sleep按钮的事件响应完。

import javax.swing.*;

import java.awt.*;

import java.awt.event.*;

 

class Hang extends JFrame

{

    public Hang()

    {   JButton b1 = new JButton( "Sleep" );

        JButton b2 = new JButton( "Hello" );

 

        b1.addActionListener

        (   new ActionListener()

            {   public void actionPerformed( ActionEvent event )

                {   try

                    {   Thread.currentThread().sleep(5000);

                    }

                    catch(Exception e){}

                }

            }

        );

 

        b2.addActionListener

        (   new ActionListener()

            {   public void actionPerformed( ActionEvent event )

                {   System.out.println("Hello world");

                }

            }

        );

 

        getContentPane().setLayout( new FlowLayout() );

        getContentPane().add( b1 );

        getContentPane().add( b2 );

        pack();

        show();

    }

 

    public static void main( String[] args )

{  

new Hang();

    }

}

大多数的书籍中讨论的Java GUI都回避了线程的问题。在现实中,对于UI事件采取单线程的方法都是不可取的。所有成功的UI程序都有下面几个共同点:

l         UI必须就程序的运行状态进程,给用户一些回馈信息。简单的弹出一个显示程序正在做的事情的对话框是不足够的。你必须告诉用户操作的运行进度(例如一个带有百分比的进度条)。

l         必须做到当底层系统状态改变时,不会为了更新窗口而把整个UI重绘。

l         你必须使你的程序做到,当用户点击Cancel按钮时,你的程序能够立即响应,并及时终止。

l         必须做到当一个需要长时间运行的操作正在运行时,用户可以在你的UI界面上做其它的操作。

这是条规则可以用一句话来总结:不允许死锁的UI界面出现,不允许当程序运行一个

耗时很长的操作时,忽略掉用户其他的操作,如鼠标点击和键盘事件,因此不允许在监听器窗口中,运行长时间的操作。耗时操作必须在后台的其他线程运行。因此,真正的程序在任何时候都会2个以上的线程在跑。

JavaScript笔记整理——驯服线程和定时器

定时器提供了一种让一段代码在一定毫秒之后,再异步执行的能力。由于Js是单线程的(同一时间只能执行一处Js代码)。定时器提供了一种跳出这种限制的方法,以一种不太直观的方式来执行代码。需要注意的是,定时器...
  • u014695532
  • u014695532
  • 2016年06月24日 16:23
  • 619

读《驯服烂代码——在编程操练中悟道》

读《驯服烂代码——在编程操练中悟道》 第2章 按图索骥地编写代码 第4章 调试一下 第5章 用TDD重做编程操练题目 第6章 消除假数据所带来的重复代码 第8章 嗅出代码腐臭和新的测试点 第9章 测试...
  • q547550831
  • q547550831
  • 2016年06月26日 19:59
  • 2835

驯服最难以捉摸的野兽──创新

管理思想本质上是一种流行风尚,但也有一些受人喜爱的主题,从来不曾失宠过。创新是常青的主题,没有把创新列为前四个或五个优先要务的CEO,是难得一见的。 但是,创新是个难以捉摸的野兽。姑且不论一...
  • wesay1
  • wesay1
  • 2015年07月12日 13:11
  • 387

对Java线程安全与不安全的理解

当我们查看JDK API的时候,总会发现一些类说明写着,线程安全或者线程不安全,比如说StringBuilder中,有这么一句,“将StringBuilder 的实例用于多个线程是不安全的。如果需要这...
  • fuzhongmin05
  • fuzhongmin05
  • 2017年03月01日 16:44
  • 2836

如何终止java线程

终止线程的三种方法      有三种方法可以使终止线程。      1.  使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。      2.  使用stop方法强行终...
  • anhuidelinger
  • anhuidelinger
  • 2013年09月16日 19:51
  • 158979

Java中的线程

转载请标明出处:http://blog.csdn.net/zhangxingping Java中的线程 进程和线程 在并发性程序中,有两个基本的执行单元:进程和线程。在Java编程语言中,并发编程...
  • zhangxingping
  • zhangxingping
  • 2013年03月04日 17:19
  • 10440

Java线程(四):线程中断、线程让步、线程睡眠、线程合并

最近在Review线程专栏,修改了诸多之前描述不够严谨的地方,凡是带有Review标记的文章都是修改过了。本篇文章是插进来的,因为原来没有写,现在来看传统线程描述的不太完整,所以就补上了。理解了线程同...
  • ghsau
  • ghsau
  • 2013年12月26日 20:29
  • 32553

Java线程的5种状态及切换(透彻讲解)

Java中的线程的生命周期大体可分为5种状态。 1. 新建(NEW):新创建了一个线程对象。 2. 可运行(RUNNABLE):线程对象创建后,其他线程(比如main线程)调用了该对象的star...
  • pange1991
  • pange1991
  • 2016年12月24日 16:57
  • 7089

Java多线程和操作系统多线程关系

这篇文章要讨论的是Java编程中的多线程和操作系统中的多线程的区别问题。 线程状态。首先两者的线程状态是一样的。(创建、就绪、执行、阻塞、终止),其实这五个状态也是进程的状态。 那么Java中的多线程...
  • yangmx_5
  • yangmx_5
  • 2017年03月29日 15:07
  • 1694

Java并发编程:线程池的使用(非常棒,通俗易懂)

Java并发编程:线程池的使用   在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:   如果并发的线程数量很多,并且每个线程都是执行一个时间...
  • u011531613
  • u011531613
  • 2017年03月13日 16:56
  • 14762
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:驯服Java线程(一)
举报原因:
原因补充:

(最多只允许输入30个字)