﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-不能停止-文章分类-java</title><link>http://www.blogjava.net/josephguan/category/4201.html</link><description>运动，游玩，学习，我的爱不能停止</description><language>zh-cn</language><lastBuildDate>Wed, 28 Feb 2007 01:08:09 GMT</lastBuildDate><pubDate>Wed, 28 Feb 2007 01:08:09 GMT</pubDate><ttl>60</ttl><item><title>java笔记之二(线程)</title><link>http://www.blogjava.net/josephguan/articles/17043.html</link><dc:creator>快乐的射手</dc:creator><author>快乐的射手</author><pubDate>Thu, 27 Oct 2005 05:31:00 GMT</pubDate><guid>http://www.blogjava.net/josephguan/articles/17043.html</guid><wfw:comment>http://www.blogjava.net/josephguan/comments/17043.html</wfw:comment><comments>http://www.blogjava.net/josephguan/articles/17043.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/josephguan/comments/commentRss/17043.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/josephguan/services/trackbacks/17043.html</trackback:ping><description><![CDATA[<P>线程<BR>1.程序如果只有后台进程而没有一个前台进程，那么整个java程序就会结束。用setDaemon(true)可以把线程设为后台线程，普通创建的线程都是前台线程。<BR>2.一个线程类继承Thread类，这个子类实现run方法，run方法处理的事物的处理。启动线程用start方法。[thread类本身的run方法是空的，所以需要子类去实现，start方法也是thread类里继承过来的，由于java的多态性，所以start方法会启动子类的run方法]<BR>3.join()方法可以合并线程，如果不带参数表示永久合并，如果带参数表示线程合并多少豪秒后又分开执行</P>
<P>class ThreadDemo<BR>{<BR>&nbsp;&nbsp;&nbsp; public static void main(String [] args)<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread tt = new TestThread();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //tt.setDaemon(true);把线程tt置为后台线程<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tt.start();//这个方法会自动去调用tt的run（）<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int index = 0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(true)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(index++ == 100)//执行100次后合并线程<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try{tt.join(10000);//把tt线程合并到主线程10秒,如果这里是没有参数，那么就永远执行run这&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //个线程，因为这个线程是个死循环，下面的语句就执行不到了，哈哈}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(Exception e){}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("main()"+Thread.currentThread().gerName()//得到当前执行线程的名字);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }<BR>}</P>
<P>class TestThread extends Thread<BR>{<BR>&nbsp;&nbsp; public void run()<BR>&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(true)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("run()"+Thread.currentThread().gerName()//得到当前执行线程的名字);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp; }<BR>}</P>
<P>以上说了如何用继承Thread类来创建线程，还有一种方法是类来实现Runnable接口来创建线程<BR>class TestThread extends Thread 这个就要改成 class TestThread implements Runnable<BR>而main中的Thread tt = new TestThread(); 就要改成 Thread tt = new Thread(new TestThread());这里接受的类型是Runnable型的</P>
<P>那么就出现了一个问题，既然两种方法都可以创建线程，那么有什么区别呢？我们来看一个铁路模拟售票系统：<BR>有100张票，我们启动4个线程来卖他们：<BR>class ThreadDemo<BR>{<BR>&nbsp;&nbsp;&nbsp; public static void main(String [] args)<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 如果用这种写法，你会发现实际是启动了4个线程，然后4个线程都有各自的100张票，各买各的，所以这样是错的。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new TestThread(); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new TestThread(); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new TestThread(); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new TestThread(); */</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*如果是这种写法，从输出结果中我们发现无论start了多少次，实际还是一个线程，所以这样也是错的。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TestThread tt = new TestThread();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tt.start();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tt.start();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tt.start();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tt.start();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; }<BR>}</P>
<P>class TestThread extends Thread<BR>{<BR>&nbsp;&nbsp; int tickets = 100;<BR>&nbsp;&nbsp; public void run()<BR>&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(true)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(tickets&gt;0)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(Thread.currentThread().gerName()+"is saling ticket "+tickets--);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp; }<BR>}<BR>这种情况下我们就使用runnable了。请看：<BR>class ThreadDemo<BR>{<BR>&nbsp;&nbsp;&nbsp; public static void main(String [] args)<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TestThread tt = new TestThread();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new Thread(tt).start();//四个线程调用同一个线程对象<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new Thread(tt).start();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new Thread(tt).start();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new Thread(tt).start();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; }<BR>}</P>
<P>class TestThread implements Runnable<BR>{<BR>&nbsp;&nbsp; int tickets = 100;<BR>&nbsp;&nbsp; public void run()<BR>&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(true)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(tickets&gt;0)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(Thread.currentThread().gerName()+"is saling ticket "+tickets--);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp; }<BR>}</P>
<P><BR>总结：使用runnable接口创建多线程比继承thread要灵活。他适合多个相同的程序代码的线程去处理同一资源的情况。</P>
<P>多线程的应用：<BR>1.网络聊天工具开发<BR>&nbsp; 一个线程负责发消息，一个负责收消息。两者互不干扰，如果是单线程，那么就可能前面在等待，而后面就接收不了消息。<BR>2.大量数据库记录的复制。<BR>&nbsp; 如果一个复制要花3天时间，那么当你中途觉得没有必要，要停止的时候，你发现你不能让他停下来。而多线程的情况，一个<BR>&nbsp; 现成负责拷贝，是个无限循环<BR>&nbsp; while(bStop)<BR>&nbsp; {get data<BR>&nbsp;&nbsp; copy data}<BR>&nbsp; 另一个现成监督是否有键盘按下，也就是把原本为true的变量bstop置为false。&nbsp;&nbsp; bStop = false;当另一线程监视到变量&nbsp; 变化时会停止程序<BR>3.www服务器为每一个来访者创建一个线程</P>
<P><BR>线程安全问题：<BR>我们在上面做的铁路模拟兽票系统有个问题：线程安全问题！<BR>假如当tickets==5的时，系统正好正好要执行tickets--，而还美意执行这个的时候，cpu被切换到另一个线程。那么tickets仍然是5，所以很坑5这张票打印了2次，另一种情况：当票为1的时候系统刚好要打印出1，而这个时候cpu马上切换到了其他线程，它发现票还是1，所以通过了判断大于0，所以打印出了票1。而这个时候票--为0，cpu切换到了刚才的线程，由于刚才的线程在执行打印，所以把票0给打印出来，这些都造成了线程的安全问题</P>
<P>所以我们要把if语句块作为一个原子，放到synchronized()里面。synchronized()里面必须有参数，比如<BR>String str = new String("");<BR>然后把if语句块放到synchronized(str){ if... }里面&nbsp; 这样就实现了同步，避免了线程的不安全。<BR>另外，我们如果希望一个方法是线程安全的，那么我们可以直接在方法名前写上synchronized关键字，比如：<BR>public synchronized void sale(){......} //实际上这种情况下synchronized使用的同步对象是this<BR>注意：str的定义必须放到run方法之外，这个对象应该是全局的，这样才能作为锁旗标！（系统会自动对这个对象进行标识）</P>
<P>线程执行的内部机制：<BR>new Thread(tt).start();<BR>执行start并没有马上去执行线程的run方法，而是再向下继续执行一会，因为cpu还没有这么快就切换到线程上，要想让他马上切换，可以在start后写上：try(Thread.sleep(1);//哪怕是一秒，他也会切换)catch(Exception e){}</P>
<P>如果把代码块的同步用synchronized(this),那么代码块会和有synchronized的方法同步！<BR><BR>1：31 为止 5</P>
<P>类似下面的代码在多线程调用它的时候也要注意线程安全问题：<BR>public void push(char c)<BR>{<BR>&nbsp; data[index] = c;<BR>&nbsp; index++;<BR>}</P>
<P>另外有一场景[线程间通信问题]：生产者不停地产生一组数据，消费者不停地去取数据，数据都在缓存中，<BR>class Producer implements Runnable<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Q q;<BR>&nbsp;public Producer(Q q)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.q = q;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void run()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i = 0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(true)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(i==0)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {q.name = "zhangsan";<BR>&nbsp;&nbsp;&nbsp; try{Thread.sleep(1);}catch(Exception e){}//用sleep来模拟cpu切换的现象<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q.sex = "male";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {q.name = "lisi";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q.sex = "female";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp; i = (i+1)%2;&nbsp; //使i在0和1之间切换<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>}<BR>class Customer implements Runnable<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Q q;<BR>&nbsp;public Customer(Q q)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.q = q;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void run()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(true)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;System.out.println(q.name);<BR>&nbsp;&nbsp;System.out.println(":"+q.sex);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>}<BR>class Q<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String name = "unknow";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String sex = "unknow";<BR>}</P>
<P>//run class<BR>class ThreadCommunation<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void main(String [] args)<BR>&nbsp;{<BR>&nbsp;&nbsp;Q q = new Q();<BR>&nbsp;&nbsp;new Thread(new Prodecer(q)).start();<BR>&nbsp;&nbsp;new Thread(new Customer(q)).start();<BR>&nbsp;}</P>
<P>}<BR>运行后我们会发现名字和性别并没有对应起来，这是因为线程没有同步的问题，要解决这个问题，只需要在两个类的while里<BR>分别加上synchronized(q){}语句块，因为他们都使用同一个对象q，所以用q作为同步监视器<BR>&nbsp; 上面的代码还不是很完善，因为有当消费者取得同步监视器却发现缓冲区根本没有数据的情况，那怎么办？或者当生产者在</P>
<P>取得同步监视器开始生产数据的时候又取得了同步监视器开始放数据，这样就会把原先的数据覆盖！我们使用了wait和notify</P>
<P>对程序修改如下：<BR>class Producer implements Runnable<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Q q;<BR>&nbsp;public Producer(Q q)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.q = q;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void run()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i = 0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(true)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;synchronized(q)<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp; if(q.bFull)//如果缓冲区是满的 有数据的 那么生产者线程应该wait等待消费者来取数据<BR>&nbsp;&nbsp;&nbsp;try{q.wait();}catch(Exception e){}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(i==0)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {q.name = "zhangsan";<BR>&nbsp;&nbsp;&nbsp; try{Thread.sleep(1);}catch(Exception e){}//用sleep来模拟cpu切换的现象<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q.sex = "male";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {q.name = "lisi";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q.sex = "female";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; q.bFull = true;<BR>&nbsp;&nbsp;&nbsp; q.notify();//通知消费者有数据要他来取数据<BR>&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp; i = (i+1)%2;&nbsp; //使i在0和1之间切换<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>}<BR>class Customer implements Runnable<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Q q;<BR>&nbsp;public Customer(Q q)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.q = q;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void run()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(true)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;synchronized(q)<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;if(!q.bFull)&nbsp; //缓冲区为空的时候交出同步监视器开始等待<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try{q.wait();}catch(Exception e){}<BR>&nbsp;&nbsp;System.out.println(q.name);<BR>&nbsp;&nbsp;System.out.println(":"+q.sex);<BR>&nbsp;&nbsp; &nbsp;&nbsp;q.bFull = false;&nbsp; //取走数据后缓冲区为空<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp; &nbsp;&nbsp;q.notify(); //通知生产者线程开始执行，这个notify与Producer中的wait对应</P>
<P>&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>}<BR>class Q<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String name = "unknow";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String sex = "unknow";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boolean bFull = false;<BR>}</P>
<P>//run class<BR>class ThreadCommunation<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void main(String [] args)<BR>&nbsp;{<BR>&nbsp;&nbsp;Q q = new Q();<BR>&nbsp;&nbsp;new Thread(new Prodecer(q)).start();<BR>&nbsp;&nbsp;new Thread(new Customer(q)).start();<BR>&nbsp;}</P>
<P>}</P>
<P>注意：wait和notify方法必须是synchronized的监视器对象的方法，既如果有<BR>synchronized(q),那么就应该q.wait();q.notify(); 如果不写对象，他会默认是this对象<BR>而有可能导致运行时错误[编译没有错误]</P>
<P>任何对象都有wait,notify,notifyAll方法，<BR>wait：告诉当前线程放弃监视器并进入睡眠状态直到其他线程进入同一监视器并调用notify为止；<BR>notify：唤醒同一对象监视器中调用wait的第一个线程。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用于类似饭馆有一个空位后通知所有等候就餐的顾客中的第一位可以入座的情况。<BR>notifyAll：唤醒同一对象监视器中调用wait的所有线程。具有最高优先级的线程首先被唤醒并执行。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用于类似某个不定期的培训班终于招生满额后，通知所有的学员都来上课的情况。</P>
<P><BR>实际上上面的代码有些乱，这是因为程序的结构设计不够合理，应该把数据的放和取放到q类中，然后在<BR>这两个方法名前加上关键字synchronized，类似<BR>public synchronized void put(String name,String sex)<BR>{<BR>&nbsp; if(bFull)<BR>&nbsp;&nbsp;&nbsp;&nbsp; try{wait();}catch(Exception e){}<BR>&nbsp; this.name = name;<BR>&nbsp;&nbsp; try{Thread.sleep(1);}catch(Exception e){}<BR>&nbsp; this.sex = sex;<BR>&nbsp; bFull = true;<BR>&nbsp; notify();<BR>}<BR>我们给别人提供的类是线程安全的，类似上面的代码。别人在使用这个类的时候就不需要考虑线程安全问题，反之，就需要在</P>
<P>外面处理线程安全问题</P>
<P>控制线程的生命周期：<BR>class ThreadLife<BR>{<BR>&nbsp;public static void main(String [] args)<BR>&nbsp;{<BR>&nbsp;&nbsp;ThreadTest tt = new ThreadTest();<BR>&nbsp;&nbsp;new Thread(tt).start();<BR>&nbsp;&nbsp;for(int i=0;i&lt;100;i++)<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;if(i==50)<BR>&nbsp;&nbsp;&nbsp;&nbsp;tt.stopMe();<BR>&nbsp;&nbsp;&nbsp;System.out.println("main() is runing");<BR>&nbsp;&nbsp;}<BR>&nbsp;}<BR>}</P>
<P>class ThreadTest implements Runnable<BR>{<BR>&nbsp;private boolean bStop = false;<BR>&nbsp;public void stopMe()<BR>&nbsp;{<BR>&nbsp;&nbsp;bStop = true;<BR>&nbsp;}<BR>&nbsp;public void run()<BR>&nbsp;{<BR>&nbsp;&nbsp;while(!bStop)<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;System.out.println(Thread.currentThread().getName()+"is running");<BR>&nbsp;&nbsp;}<BR>&nbsp;}<BR>}</P>
<P>&nbsp;</P>
<P>&nbsp;</P><img src ="http://www.blogjava.net/josephguan/aggbug/17043.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/josephguan/" target="_blank">快乐的射手</a> 2005-10-27 13:31 <a href="http://www.blogjava.net/josephguan/articles/17043.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java笔记之一</title><link>http://www.blogjava.net/josephguan/articles/17042.html</link><dc:creator>快乐的射手</dc:creator><author>快乐的射手</author><pubDate>Thu, 27 Oct 2005 05:30:00 GMT</pubDate><guid>http://www.blogjava.net/josephguan/articles/17042.html</guid><wfw:comment>http://www.blogjava.net/josephguan/comments/17042.html</wfw:comment><comments>http://www.blogjava.net/josephguan/articles/17042.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/josephguan/comments/commentRss/17042.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/josephguan/services/trackbacks/17042.html</trackback:ping><description><![CDATA[<P>差不多扔下java1年多了,现在回来看看才明白什么叫一日千里,我还是想把以前丢下的东西找回来,所以看看资料.把笔记放在这里<BR><BR>float fl=3.5; //错误 因为3.5是double的 应该是：float fl=3.5f;</P>
<P>byte b = 3;<BR>b = b - 1;<BR>以上写法错误 因为如果表达式中有int型数字，那么所有的byte ，shot，char的值都将被提升到int；同样，long，float, double也是如此</P>
<P>System.out.println('a'+1);&nbsp; 结果是98</P>
<P>System.out.println(""+'a'+1); 结果是a1</P>
<P>static void drawTech(int x,int y)<BR>{.........}<BR>这个方法可以直接使用而不需要new，比如在main方法中写drawTech(3，5）；</P>
<P>System.out.println("2+5="+getAres(2,5));而不是<BR>System.out.println("2+5="，getAres(2,5));</P>
<P>非法参数的检查用return;直接返回</P>
<P>函数的重载就是在一个类中允许同时存在一个以上的同名函数，只要它们的参数个数或者类型不同即可</P>
<P>小数之间的除 结果会保留小数部分<BR>整数之间的除 结果抛弃小数部分<BR>-------------------------<BR>int x=5,y;<BR>int y=x/2;//结果是2<BR>--------------------------<BR>int x=5,y;<BR>float f=x/2;//结果是2.0<BR>----------------------------<BR>int x=5,y;<BR>float f=（float）x/2;//结果是2.5&nbsp; 这里发生了表达式数据类型提升<BR>------------------------------------------------------------<BR>int x=3510;x=x*1000/1000;&nbsp; 结果是3000<BR>----------------------------------------<BR>int x=5,y;<BR>y = x%2;//结果是 1<BR>--------------------------------<BR>int x=5,y;<BR>y = -x%2;//结果是 -1<BR>-------------------------------<BR>int x=5,y;<BR>y = x%-2;//结果是 1&nbsp; 表示取摸时 摸数如果是负数 那么负号忽不计算<BR>--------------------------------------<BR>安排房间题目，共有x个学生，每个房间住6人，用一个公式计算他们要住的房间数？<BR>解答：有些人是x/6+1； 显然在x为30的时候就不对了，正解是：（x+5）/6；<BR>这种算法还可以用在查看留言版的分页显示上，x是总留言数，6是每页显示数，结果就是总共多少页面<BR>-----------------------------------------------------------------------------------<BR>假设要让x的值在0到9之间循环变化，写出代码：<BR>int x=0;<BR>while(true)<BR>{<BR>x=(x+1)%10;<BR>}<BR>这个可以用在循环10副图的显示上<BR>-------------------------------------<BR>x = 0x80000000;<BR>y = x&gt;&gt;1;//有符号移位最高位补的是原来的最高位，原来是1就补1，是0补0<BR>System.out.println(Integer.toHexString(y));//将int的y转化为16进制<BR>y = x&gt;&gt;&gt;1;//无符号移无论原来是1还是0都补0<BR>System.out.println(Integer.toHexString(y));//将int的y转化为16进制<BR>-----------------------------------------------------------------------<BR>byte，short,char,int,long都可以移位运算<BR>低于int的操作数先自动转int再移<BR>int型移 最多移31位，因为int最大是32位的 系统将操作数对32取模，得到的结果才是真正的依的位数，a&gt;&gt;33 和a&gt;&gt;1结果是一样的<BR>long型是对64取模<BR>x&gt;&gt;1和x/2结果一样&nbsp; x&lt;&lt;2和x*4结果一样<BR>-----------------------------------------------------<BR>从键盘读取输入字符的整数值System.in.read();<BR>以下代码为不断读入键盘值，如果是q，那么退出，如果不是q，打印字符<BR>try<BR>{<BR>x=System.in.read();<BR>}<BR>catch(Exception e){}<BR>while(x!='q')<BR>{<BR>&nbsp;&nbsp;&nbsp; System.out.println((char)x);<BR>&nbsp;&nbsp;&nbsp; try{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x=System.in.read();<BR>&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp; catch(Exceotion e){}<BR>}<BR>---------------------------------<BR>声明数组可以：一开始就对数组赋值的叫静态数组<BR>int a[]={1,2,3};<BR>也可以<BR>int []a=new int[]{1,2,3}<BR>如果没有赋值，比如<BR>int []a=new int[]；<BR>打印出来默认的全为0<BR>如果这么定义一个数组int [] y;然后就拿来使用那么是编译通不过的，因为没有初始化，一个数组没有初始化，也没有指向堆中的任何地方，所以也没有默认值<BR>------------------------<BR>int a[4];//声明数组时 不能指定长度，编译将出错。和c不一样<BR>---------------------------------------------------------<BR>int[] x=new int[100];<BR>x= null;<BR>x[1]=3;<BR>这样的代码编译通过，运行出错：空指针错误。 因为x数组指向的是空，所以就没有所谓的第一个元素第二个元素 这点需要注意<BR>同理，当我们调用一个返回的对象的功能时，如果不对这个对象进行检查，而这个对象是空，那么就可能是这种空指针异常<BR>-----------------------------------------------------------------------------------------------------<BR>遍历二维数组<BR>int [][] xx = new int[2][3];<BR>for(int i=0;i&lt;xx.length;i++)<BR>{ <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int j=0;j&lt;xx[i].length;j++)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(xx[i][j]);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P>}<BR>-----------------------------------------<BR>int []a=new int[]{9,4,3,8};<BR>Arrays.sort(a);//从小到大排序</P>
<P><BR>2下结束</P><img src ="http://www.blogjava.net/josephguan/aggbug/17042.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/josephguan/" target="_blank">快乐的射手</a> 2005-10-27 13:30 <a href="http://www.blogjava.net/josephguan/articles/17042.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>