个人管理功能

在CSDN Blog撰写技术文章,即有机会入选CSDN技术中心,现在就去免费注册!已注册用户,点击登录

搜索
热门标签
专题历史

有人说SOA是一种IT策略,有人说SOA是一种架构理念,还有人说SOA是一种服务。SOA到底是什么?它将带来什么?软件产业的变革亦或是新的机遇下的挑战?业界权威专家带领我们一起去深究,去探索。BEA三位重量级专家与您共同探讨SOA

随着WPF/E更名为正式名称Silverlight,以及Silverlight 1.1 Alpha 版本的发布,答案变得清晰,而且令人兴奋! - 一个跨操作系统,跨浏览器的Web应用平台出现了。Silverlight 这样一个4.5MB的浏览器插件(1.1 Alpha文件)是如何做到的这些的?周岳: SilverLight-Web应用的一道强光

中国移动用户数量在大踏步地发展与增长,根据产业部的数据,仅三月就新增了670万户。预估计6月份之后,中国很快将迎来第五亿手机用户(平均不到3人拥有一台手机)而J2ME做为最重要的手机跨平台技术,凭借Java平台以其良好的开放性和支持能力,得到了众多手机厂商的支持。对众多开发者来说,J2ME程序易于移植,轻松实现“一次编写,到处运行”。J2ME系列开发专题,将带你从最基本的工具安装,环境配置开始,进入移动应用开发的世界。
 
CSDN移动开发系列之-“J2ME开发实训”

7月31日-8月1日,即将在上海召开甲骨文全球大会•亚太地区会议同期举行的甲骨文开发者大会,这是一项付费参加的面向开发人员的活动。在甲骨文开发者大会期间,您将听到世界一流的专家讲述如何使用Java、.NET、XML和PL/SQL以及Ajax、PHP、Spring、Groovy on Rails等流行技术来简化开发过程。在为期两天的甲骨文开发者大会中,您将能够提高自身的开发技能,扩充知识,参加几十场由专家主持的深入细致的技术讲座并在专家的辅导下进行上机操作、了解高级技能和获得详细指导。在甲骨文开发者大会期间,您有机会直接向业界一流的技术专家和开发人员请教。欢迎参加甲骨文全球大会·2007·亚太地区开发者大会

2007年6月29日,自由软件基金会宣布,其创始人Richard Stallman将在GNU的网站上,在本周太平洋时间星期五上午9点通过视频发布GPLv3。本来,GPL并不是所有开源组织所认可的协议。其从出现以来一直存在争议,GPL被认为是一种“病毒式”的协议,BSD的fans和老牌Unix黑客们认为,他们编写Unix的年头都比GPL声明要长得多,他们更愿意采用比GPL更加的自由的BSD协议。今天,开源社区中有70%左右的项目采用了GPL。很多在开源社区的老牌黑客们认为,Richard Stallman所鼓吹开源软件的言行与当年卡尔·马克思号召产业无产阶级反抗工作的努力如出一辙。在GPLv3的第三版修订案发布时,开源软件团体中的许多成员都反对这种协议。尤其是Linux的核心开发小组,其中29个高级架构师有28个反对这个协议。Linus Torvalds称这个协议有“宗教性质”,并公开反对。而整个软件行业特别是开源社区对GPLv3的争论也愈演愈烈。GPLv3:大教堂和集市的新一轮对抗

2007年7月14日由CSDN与ThoughtWorks联合主办的第二届“敏捷中国”技术大会在北京丽亭华苑酒店召开,多位开源社区和ThoughtWorks公司的技术领袖即将带来精彩的演讲。本次“敏捷中国”技术大会集中展现塑造敏捷企业所需的方方面面:业界领先的敏捷项目管理工具;极大提升软件开发效率的新语言和新框架;数据库领域的敏捷实践;全方位的敏捷项目管理指导;还有身临其境的亲身体验。来自开源社区和ThoughtWorks公司的技术领导者们将带领听众全面感受敏捷企业。“敏捷中国大会”现场直击

从2004年起,在每年的夏季,CSDN都会举办面向中国程序员的大型网上调查活动。这是中国样本最丰富的开发者社区调查,持续、全面和深入地反映了中国开发者社群自身状况、各项技术、工具、产品的使用状况和发展趋势,是完整、准确地了解中国开发者市场的重要参考资料。本次调查覆盖基础信息、.NET、Java、C/C++、Web开发、数据库应用开发、软件工程及项目管理、移动及嵌入式开发、开放源代码、企业信息化等10个领域。还有惊喜大奖等着你哦,赶快进入吧! 2007中国软件开发者大调查正式启动

推荐作者
  • 大宝大宝

    时间如流水,知惜方成功。

  • SkymanSkyman

    江苏人氏,梅兰芳之老乡。现游学渝州之最...

  • ralph623ralph623

新进作者
  • 冲 s冲 s

  • 小鱼小鱼

  • 棱角棱角

    多年J2EE构架设计与开发经验,专注于企业信息系统建设,精通Java设计模式,并能熟练的运用到企业开发中。 精通Struts与Spring框架。数据库方面精通Oracle数据库,从事过数据库方面的开发以及oracle优化方面的工作。

最新技术图书推荐
Java线程学习和总结

发表日期:2007-1-10
更新日期:2007-1-10
作者文章阅读次数:2744

源自:梵天 (个人网站) 标签:java

您认为本文应该得        共有6人参与打分打印|收藏|讨论|投诉

最近比较系统的学习了Java线程,然后花了些时间总结了一下。正文是这个学习笔记的全部,但是如果看起来不是很方便的话,我这里有做好的PDF文档,当然源代码也有,如果需要,可以发Mail到: fantian830211@163.com ,而且衷心的感谢您的指点。

线程是Java的一大特色,从语言上直接支持线程,线程对于进程来讲的优势在于创建的代价很小,上下文切换迅速,当然其他的优势还有很多,缺点也是有的,比如说对于开发人员来讲要求比较高,不容易操作,但是Java的线程的操作已经简化了很多,是一个比较成熟的模型。很多时候,我们都用不到线程,但是当我们有一天不走运(或者走运)的时候,我们必须要面对这个问题的时候,应该怎么办呢?本文是我的学习笔记和一些总结,试图解决这个问题,引领还没有接触过Java 线程的开发人员进入一个Java线程的世界,其实很多东西在网路上已经有朋友总结过了,不过我感觉没有比较循序渐进,要么太基础,要么太高深,所以这边我由浅到深的总结一下。但是很显然,我的资历尚浅,能力也很有限,如果有什么错误还望不吝赐教!麻烦发送mail到:fantian830211@163.com 而且,这些大部份的都有源码,如果需要也可以发mail到这个邮箱,真的非常希望有人能指正我的错误!

(一) 基本的API介绍

1.   如何创建一个可以执行的线程类

       创建一个线程有两个办法:继承Thread类或者实现Runnable接口。

       首先:继承Thread

       这里一般只需要我们来重写run这个方法。下面是代码:

public class SimpleThread extends Thread {

       public SimpleThread() {

              start();

       }

       @Override

    public void run() {

              while (true) {

                     System.out.println(this);

                     // Imply other thread can run now, but we cannot assume that it will

                     // work well every time, actually , most of time we can get the same

                     // result, but not to a certainty.

                     // yield();

                     try {

                            sleep(100);

                     } catch (InterruptedException e) {

                            e.printStackTrace();

                     }

              }

       }

}

其次:实现Runnable接口,代码如下:

       Public class Inner implements Runnable {

              private Thread thread;

              public Inner(String name) {

                     thread = new Thread(this, name);

                     thread.start();

              }

              public void run() {

                     while (true) {

                     try {

                                   Thread.sleep(10);

                            } catch (InterruptedException e) {

                                   throw new RuntimeException(e);

                            }

                     }

              }

2.   几个常用的API

这边介绍几个常见而且重要的的线程API,这边JDK文档有更加详细的说明,其实JDK的文档就是个很好的学习资料,常备很重要哦!

方法

说明

start

使线程开始执行,实际上这个方法会调用下面的run这个方法,如果这个线程已经开始执行,则会扔出IllegalThreadStateException

sleep

是当前已经运行的线程休眠一段时间。如果当前线程已经被别的线程中断的话,将会扔出InterruptedException,而且interrupted标志也会被清空。这个方法有两个版本,具体参看JDK文档。

run

线程执行的业务逻辑应该在这里实现。

join

等待另外一个线程死亡。如果当前线程已经被别的线程中断的话,将会扔出InterruptedException,而且interrupted标志也会被清空。

yield

使当前线程临时的中断执行,来允许其他线程可以执行,因为Java的线程模型实际上映射到操作系统的线程模型,所以对于不同的操作系统,这个方法的就有不同的意义。对于非抢占式Operating System,这个方法使得其他线程得到运行的机会,但是对于抢占式的OS,这个方法没有太多的意义。关于这个方法,后边还有更多的介绍。

wait

Wait方法和后边的两个方法都来自Object。看过Java源码的可以知道,这三个方法都是Native方法,使比较直接的和操作系统打交道的方法。

这个方法的作用是让当前线程等待,直到被唤醒或者等待的时间结束。当前线程进入等待队列的时候,会放弃当前所有的资源,所以当前线程必须获得这些对象的Monitor,否则会扔出IllegalMonitorStateException 关于wait方法的更多,后边会有介绍到。

notify

通知其他线程可以使用资源了。这个方法的使用要求很多,总之需要当前线程获得被调用的notify方法的对象的monitor。比如:

                                                 synchronized (person) {

                                                        person.notify();

                                                 }

其实,获得monitor的方法还有别的,这里简单介绍一下:

1.         执行这个对象的一个同步的方法

2.         执行这个对象的同步块

3.         执行一个同步的静态方法

notifyAll

除了通知所有的线程可以准备执行之外,跟上面的方法要求一样。但是只有一个线程会被选择然后执行,这个就跟优先级和其他状态有关系了。

interrupt

中断线程。

这边只是介绍了几个常用的API,但是非常重要,其他的API可以查看JDK的相关文档。但是在操作系统的概念中,很显然,对于一个线程应该还有别的状态,对,确实还有,但是Java在实现的映射的时候,也实现了这些方法,只是不赞成使用,下面的主题将讨论这些方法以及这些方法的替代方法。

3.   已经不赞成使用的方法

对于一些不应该再使用的东西,有时候被称为反模式antipattern。这些都是概念上的东西,对于我们开发人员来讲,需要做的就是写出好的代码。

方法

说明

stop

强制使当前的线程停止执行。实际上,作为开发人员我们会意识到,线程的复杂程度是没有边际的,而这个方法这样武断的停止一个线程,必然导致问题产生。也就是说,这个方法天生就有问题。比如说一个线程掌握了很多对象,并且改变了其中一些的状态,如果突然当前对象突然被停止,将会释放这些对象的monitor,这个时候被改变状态的对象就是被损坏的对象,其他线程再来操作的时候问题就出来了。

替代的办法就是让当前线程正常结束,不使用这个方法。就是我们设置一些标志,如果这些标志满足的时候,我们结束线程。下面用JDK的例子:

    private Thread blinker;

    public void start() {

        blinker = new Thread(this);

        blinker.start();

    }

    public void stop() {

        blinker.stop();  // UNSAFE!

    }

    public void run() {

        Thread thisThread = Thread.currentThread();

        while (true) {

            try {

                thisThread.sleep(interval);

            } catch (InterruptedException e){

            }

            //do something

        }

}

修改后:

    private volatile Thread blinker;
    public void stop() {
        blinker = null;
    }
    public void run() {
        Thread thisThread = Thread.currentThread();
        //Check the flag
        while (blinker == thisThread) {
            try {
                thisThread.sleep(interval);
            } catch (InterruptedException e){
            }
            //do something
        }

}

当然如果这个方法中间有wait方法的调用的话,而且正在等待,我们可以使用这个办法来结束:

Thread.currentThread().interrupt();

然后处理InterruptedException

 

这个我也实现了避免使用stop方法的一个类,在源码中可以看到。

suspend

这个方法天生就有导致死锁的可能。如果当前线程持有很多对象的锁,但是当他suspend的时候,这些锁是不会释放的,想想就知道应该什么可能会发生,所以这个方法应该尽量不用。

这里我们有办法替代这个方法,其实根替代stop的方法差不多,就是用wait方法来实现挂起,而不是事实上的挂起。比如:

@Override

    @SuppressWarnings("static-access")

                            public void run() {

                                   while (true) {

                                          try {

                                                 Thread.currentThread().sleep(1000);

                                                 // Double check

                                                 if (isSuspended) {

                                                        synchronized (this) {

                                                               while (isSuspended) {

                                                                      wait();

                                                               }

                                                        }

                                                 }

                                          } catch (InterruptedException e) {

                                                 // null

 

                                          }

                                   }

                            }

    这样做可以同样实现挂起,但是仍然会释放资源。

resume

很显然,这个方法和上面的方法是对应的,所以上面用了wait方法来替代,所以这边应该用notify这个方法或者notifyAll这个方法来替代。

 

其实这边可以把上面的实现方式结合起来,实现一个可以安全stopsuspend的线程。这个在我的源码里有实现,但是不知道是不是对的。不过感觉原则应该没有问题,那就是设置标志来结束或者挂起线程,而不是使用这些过时的方法。

4.   跟线程相关的关键字

跟线程相关的关键字我能够想到的就下面两个:

关键字

说明

volatile

这个关键字告诉编译器不要对这个属性或者值进行优化,也就是为了保证这个变量的同步性,如果这个值被更新,其他线程应该可以马上访问到最新的值,而不是“脏值”。其实这个关键字是同步互斥的一个模型,但是现在没有实现。

synchronized

给对象或者Class加锁,分为对象锁和Class锁。

对象锁只是加在当前对象上,对别的对象没有影响,这种加锁一般都是把这个关键字用在方法和同步块上面。

Class锁就是加在这个Class上面,所有的其他对象想访问这个Class的对象的任何同步方法,必须获得这个锁。这种锁一般把这个关键字用在静态方法中,或者显示的这样实现:

                                   synchronized (AClass.class) {

                                          while (isSuspended) {

                                                 wait();

                                          }

                                   }

一般我们很少用Class锁。

 

这里简单提一下monitor,个人感觉这里把monitor认为是一把锁也可以。网络上有朋友解释的比较好:在java中,每个对象只有一个相应的monitor,一个mutex,而每一个monitor都可以有多个“doors”可以进入,即,同一个monitor中被守护的代码可以在不同的地方,因为同一个对象可以出现在不同的代码段,只要mutex锁定的对象是同一个,每个入口都用Synchronized关键字表明,当一个线程通过了Synchronized关键字,它就所住了该monitor所有的doors

其实线程的使用不在于语言的API,而在于对操作系统的理解和一些常见的调度算法,其实个人理解经验比较重要,后边介绍到线程的实现模式和设计模式。其实我还是以前的想法:对于语言的学习,首先学习语法和API,然后学习如何使用这些API在语法的框架内编写出高效的程序。很显然,模式就是实现后边的重要方法。模式常见的分类有实现模式、设计模式和架构模式。这里限于本人的能力问题,没有理解到架构上面去,所以这里只是研究了前两个。

(二) 线程实现模式

实现模式这边主要参考自Effective Java这本书,至少分类是,但是很多内容应该会很不相同,当然还有Think in javaEffective Java短小精悍的一本书,其中有太多的Java的关于实现模式的建议,但是这边把这本书的内容归类到实现模式,是我个人的想法,如果有什么不正确,万望指正。但是,个人认为这些概念性的东西仍然不会损害到我们需要讨论的问题的实质。

1.         共享数据同步

上面有提到过synchronized关键字,这个关键字保证一段代码同时只能有一个线程在执行,保证别人不会看到对象处于不一致的状态中。对象将从一种一致的状态转变到另一种一致的状态,后来的线程将会看到后一种状态。

Java中,虚拟机保证原语类型(doublelong)的读写都是原子性的。即不需要同步,但是如果不对这样的数据读写进行同步,那么后果将很严重。可以参照Effective Java的解释,这里还要简单的提示意下,Effective Java中有提到double check这种方式,而且我的源代码中多次用到这种方法,单是需要提醒一下,如果用这种方式来实现singleton的话,就不可以了,因为这样有可能导致不完整的对象被使用,单是源码中的double check用的都是原语类型,所以OK 这边的建议是如果修改原语类型或者非可变类的属性,可以同步或者使用volatile关键字。如果是其他对象,必须同步。关于尽量少使用同步,这边的建议是,我们这样的初学者在不知道如何优化的情况下就不要优化,我们要的是正确的程序,而不是快的程序。

2.