powerwind 发表于 2006-4-21 13:32

JAVA多线程

那天在后院输入”线程“关键字,结果只找到hjack的一篇文章,可见这里讨论”线程“不多。这几天正好在看JAVA多线程设计,所以发个帖,大家来讨论讨论。


我们学习编程的时候,第一个程序的功能常常是输出 "HelloWrold"。
如果第一次写多线程程序,这也算是第一个HelloWrold程序了。

class Test
{
        public static void main(String[]args)
        {
                new Thread(){
                        public void run()
                        {
                                for(int i=0;i<1000;i++)
                                System.out.print("Hello ");
                        }
                }.start();

                for(int i=0;i<1000;i++)
                System.out.print("world ");

        }
}


在main方法中写了一个匿名类,run方法会输出1000个Hello。乍一看,以为输出结果是先1000个Hello,然后1000个world。实际上呢,是Hello与world交错出现。这是因为我们启动了两个线程,这两个线程会交替获得CPU时间来执行操作。
这两个线程分别是:main方法是主线程,然后它又调用Thread类的start(),从而启动了另一个线程。(注意:如果调用Thread类的run(),不会启动新线程。详情请参考JDK文档)

多线程设计首先要注意控制好多线程之间的共享与冲突。其中Single Threaded Execution Pattern是多线程程序设计的基础,不过关于这个问题在
<<JAVA多线程设计模式--Single Threaded Execution Pattern>>(http://gdutbbs.com/thread-59348-1-1.html)有详细介绍。

下面就举一例,说明线程死锁的问题。
一个人写字,要有纸和笔。假设A要求先得到笔接着得到纸就可以写一行字,然后放开纸,笔。B要求先得到笔接着得到纸就可以写一行字,然后也放开笔,纸。程序代码如下:

class Main
{
        public static void main(String[]args)
        {
                String pen=new String("pen");
                String paper=new String("paper");
                new Test("A",pen,paper).start();
                new Test("B",paper,pen).start();
        }
}
class Test extends Thread
{
        private final String pen;
        private final String paper;
        private String name;
       
        public Test(String name,String pen,String paper)
        {
                this.name=name;
                this.pen=pen;
                this.paper=paper;
        }

        public void run()
        {
                while (true)
                {
                        write();
                }
        }

        public void write()
        {
                synchronized(pen)
                {
                        System.out.println(name+" pick up the "+pen+"!");
                        synchronized(paper)
                        {
                                System.out.println(name+" pick up the "+paper+"!");
                                System.out.println(name+" write a line!");
                                System.out.println(name+" put down the "+paper+"!");
                        }
                        System.out.println(name+" put down the "+pen+"!");
                }
        }

}


执行结果:

A pick up the pen!
A pick up the paper!
A write a line!
A put down the paper!
A put down the pen!
A pick up the pen!
A pick up the paper!
A write a line!
A put down the paper!
B pick up the paper!
A put down the pen!
B pick up the pen!
B write a line!
B put down the pen!
B put down the paper!
B pick up the paper!
B pick up the pen!
B write a line!
B put down the pen!
B put down the paper!
B pick up the paper!
B pick up the pen!
B write a line!
B put down the pen!
B put down the paper!
B pick up the paper!
A pick up the pen!

在B拿到纸,A拿到笔时停住了。
如果把
               
                new Test("A",pen,paper).start();
                new Test("B",paper,pen).start();
               
                改成
               
                new Test("A",pen,paper).start();
                new Test("B",pen,paper).start();
               
                就不会发生死锁了。原因是A拿了pen,B也想拿pen,(虽然有paper也不去拿)只有等A放下pen。这样就不会出现一个在等pen一个在等paper的情况了。

对于多线程,我是初学,不对之处请见谅!

wool王 发表于 2006-4-21 16:50

楼主写得不错.支持原创,支持分享...

Leon001 发表于 2006-4-21 16:53

银行家算法

hjack 发表于 2006-4-21 19:18

呵呵.

当时有想过写写一些多线程方面的贴,

但一直很忙,没有时间去搞.

现在更加忙.

powerwind ,加油!

相信你可以做得到(还记得我的PM吗?)

powerwind 发表于 2006-4-22 11:18

Immutable问题

Immutable就没问题了。Immutable就是不可变的意思,String类就是最典型Immutable类。上面讨论到的线程死锁问题中,如果将pen和paper封装起来就不会发生死锁。但是封得要够死,(如果内部给悄悄改了就不好)也就是封成Immutable类。为了说明Immutable类,说个简单的例子。
String类是Immutable类,StringBuffer是mutable类


//Immutable的Message类
class Message
{
        private final String msg;
        public Message(String msg)
        {
                this.msg=msg;
        }

        public String toString()
        {
                return "Message:"+msg;
        }
}


//mutable的Message类
class Message
{
        private final StringBuffer msg;
        public Message(StringBuffer msg)
        {
                this.msg=msg;
//改成这样(this.msg=new StringBuffer(msg))也可以变成immutable
        }
        public String toString()
        {
                return "Message:"+msg;
        }
}


//测试类
class Main
{
        public static void main(String[]args)
        {
                StringBuffer sb=new StringBuffer("Hello");
                //String sb=new String("Hello");
                Message message=new Message(sb);
                System.out.println(message);
                //sb.replace("Hello","world");
                sb.replace(0,5,"world");
                System.out.println(message);
        }
}
//改变注释,可是看到,一个在外面给改了,一个无法改。

如果写多线程的程序时发现运行不是所期望的,可以考虑是不是有些东西在外部给改变了。我感觉这个问题应该在C++中更易出现,因为它的指针权力太大了。(猜测而已)
页: [1]
查看完整版本: JAVA多线程