-
java
2008-09-18 17:21:22
线程间的通信
wait:告诉当前线程放弃监视器,进入睡眠状态直到其他线程进入同一监视器并调用notify为止
notify:唤醒同一对象监视器中调用wait的第一个线程。用于类似饭馆有一个空位后通知所有等待就餐的顾客中的第一位可以入座的情况
notifyAll:唤醒同一对象监视器中调用wait的所有线程,具有最高优先级的线程首先被唤醒并执行。用于类似某个不定期的培训班终于招生满额后,通知所有学员都来上课的情况
class Producer implements Runnable
{
public void run()
{
Q q //定义一个缓冲区
while (true)
{ if(i==0)
{
q.name="zhangsan";
q.sex="male"
}
else
{
q.name="LISI";
q.sex="female"
}
i= (i+1)%2
}
}
}
class Consumer implements Runnable
{ Q q
public void run()
{
while (true)
{
}
}}
class Q
{
String name ="unknown"
String sex ="unknown"
} -
第五课-多线程同步问题
2008-07-01 14:59:26
多线程同步问题
*什么是线程安全
*同步代码块
*同步函数
*代码块与函数间的同步
*死锁问题
45分钟
刚才的程序有一个意外就是tickets的值
还有一种情况是tickets=0的情况时也会出现答应
class Threaddemo1
{
public static viod main(String [] args//main方法是在线程上进行的
{
TestThread tt= new TestThread ()new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();//接受tt对象,然后创建多个线程
}
}
class TestTread implments Runnable//集成接口 runnable类灵活的多
{ int tickets = 100;
public void run()
{
while (true)
{
if (tichests>0)
{ try{Tread.sleep(10);}catch(Excetption e){}_
system.out.println("run:"+Thread.currentThread().getName()+"is saling ticket"+ tickets
--)//
}
}
}
}
就打印除了0,-1,-2的情况
避免这种情况发生
保证if(tickets>0)
其他线程一定要保证一个线程中的System.println
一个程序中的只能允许一个线程可以执行的代码叫原子代码
只要将原子代码放在一个同步语句块中就可以,保证一个线程进入一个程序代码中
上面的程序中的原子代码是:
if (tichests>0)
{ try{Tread.sleep(10);}catch(Excetption e){}_
system.out.println("run:"+Thread.currentThread().getName()+"is saling ticket"+ tickets
--)
只要将它放在synchronized()
即:
class Threaddemo1
{
public static viod main(String [] args//main方法是在线程上进行的
{
TestThread tt= new TestThread ()new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();//接受tt对象,然后创建多个线程
}
}
class TestTread implments Runnable//集成接口 runnable类灵活的多
{ int tickets = 100;
String str= new String("")
public void run()
{
while (true)
{
synchronized(str);//任意类型的对象,
{
if (tichests>0)
{ try{Tread.sleep(10);}catch(Excetption e){}_
system.out.println("run:"+Thread.currentThread().getName()+"is saling ticket"+ tickets
--)//
}
}
}
}
}synchronized(str);//任意类型的对象,线程的标志为是0还是1,开始,对象的标志位是1,已进入代码,标志位制成0,如果又有一个线程进入代码,发现标志位0,就会让出cpu给其他线程,这样就保证了,只能有一个线程进入这个代码。当第一个线程执行完代码后,会把标志位制成1,变为1以后,其他线程就会进入代码块。
标志位也就是锁起位,即监视器
同步,是以牺牲系统的性能为代价的。如果程序没有线程安全问题,尽量不要用多线程。
如果把 String str= new String("")放在run()方法中就会出现不安全现象,也会打印出0,-1,-2
因为每一个线程检查的监视器不是同一个,所以就会有问题
多个线程要同步,他们使用的对象一定是同一个监视器。
还可以用同步函数来实现多线程
class Threaddemo1
{
public static viod main(String [] args//main方法是在线程上进行的
{
TestThread tt= new TestThread ()new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();//接受tt对象,然后创建多个线程
}
}
class TestTread implments Runnable
{ int tickets = 100;
String str= new String("")
public void run()
{
while (true)
{
sale();
}
}
public void sale()
{
if (tichests>0)
{ try{Tread.sleep(10);}catch(Excetption e){}_
system.out.println("run:"+Thread.currentThread().getName()+"is saling ticket"+ tickets
--)//
}
}
}
这个线程不能实现同步的
如果在函数前加一个 sychronized 关键字
即 public sychronized void sale()
就可以实现同步,如果一个方法前增加了关键字sychronized 只能有一个线程进入这个方法,其他的线程不允许进入这个方法。
sale方法使用的什么标志位?同步对象是this
代码块,函数来实现同步线程启动的内部机制
start()不是cpu马上就执行这个线程。只是线程准备到就绪状态,如果cpu还在原来的线程上执行,将还在继续。
try{Thread.sleep(1);}catch(Exception e){}方法中的监视器就是this
如果一个方法和代码块进行同步,可以在代码块中增加this这样就可以达到同步的作用
即synchronized(this)死锁的问题:
一个线程进入x监视器,另一个线程进入Y监视器,y又等x,x又等待y -
第五课-使用Runnable接口创建多线程
2008-07-01 14:58:05
三、后台线程和联合线程
*如果我们对某个线程对象在启用(调用start方法)之前调用了setDaemon(true)方法,这个线程就变成了后台线程
*对java程序来说,只要还有一个前台线程运行,这个进程就不会结束,如果一个进程中只有后台线程运行,这个进程就会结束。
*pp.join()的作用是把pp所对应的线程合并到调用pp.jion();语句的线程中(主线程)
后台例子:
class Threaddemo1
{
public static viod main(String [] args//main方法是在线程上进行的
{
Tread tt=new TestTread();
tt.setDaemon(true);
tt.start();
}
}
class TestTread extend Thread//不同
{
public void run()
{
while (true)
{
system.out.println("run:"+Thread.currentThread().getName())//
}
}
}
联合例子:
class Threaddemo1
{
public static viod main(String [] args//main方法是在线程上进行的
{
Tread tt=new TestTread();tt.start();
int index=0;
while (true)
{
if(index++==100)
try{tt.join();}catch{Exception e} //异常处理,主线程和子线程合并
//try{tt.join(10000);}catch{Exception e} //异常处理,主线程和子线程合并 10秒
system.out.println("main:"+Thread.currentThread().getName())//
}
}
class TestTread extend Thread//不同
{
public void run()
{
while (true)
{
system.out.println("run:"+Thread.currentThread().getName())//
}
}
}
runnableclass Threaddemo1
{
public static viod main(String [] args//main方法是在线程上进行的
{
Thread tt=new Thread(new TestThead());接口对象tt.start();//不再调用thread 中的run()方法,而是调用runnable接口对象的方法
int index=0;
while (true)
{
if(index++==100)
try{tt.join();}catch{Exception e} //异常处理,主线程和子线程合并
//try{tt.join(10000);}catch{Exception e} //异常处理,主线程和子线程合并 10秒
system.out.println("main:"+Thread.currentThread().getName())//
}
}
class TestTread implments Runnable//集成接口 runnable类
{
public void run()
{
while (true)
{
system.out.println("run:"+Thread.currentThread().getName())//
}
}
}直接用runnable接口实现的线程和直接用Thread对象的线程有什么区别?
调用runnable接口的start方法,就不去调用thread的start方法售票:
线程表示售票
class Threaddemo1
{
public static viod main(String [] args//main方法是在线程上进行的
{
new TestThread ().start();
new TestThread ().start();
new TestThread ().start();
new TestThread ().start();
}
}
class TestTread extends Thread//集成接口 runnable类
{ int tickets = 100;
public void run()
{
while (true)
{
if (tichests>0)
system.out.println("run:"+Thread.currentThread().getName()+"is saling ticket"+ tickets
--)//
}
}
}四个售票点是各自买各自的票,四个对象都有自己的100张票
class Threaddemo1
{
public static viod main(String [] args//main方法是在线程上进行的
{
TestThread tt= new TestThread ();
tt.start();
tt.start();
tt.start();
ttstart();
}
}
class TestTread extends Thread//集成接口 runnable类
{ int tickets = 100;
public void run()
{
while (true)
{
if (tichests)
system.out.println("run:"+Thread.currentThread().getName()+"is saling ticket"+ tickets
--)//
}
}
}
只产生一个对象,只有100张票,启动了4个start,但是代码中只启动了一个线程来启动了start方法
来买票,不能说启动多了start就会启动多个线程。要实现铁路售票,需要
创建一个资源对象,要创建多个线程,我们需要把子对象实现接口Runnable
多个线程处理一个资源对象就需要用接口Runnable
class Threaddemo1
{
public static viod main(String [] args//main方法是在线程上进行的
{
TestThread tt= new TestThread ()new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();//接受tt对象,然后创建多个线程
}
}
class TestTread implments Runnable//集成接口 runnable类灵活的多
{ int tickets = 100;
public void run()
{
while (true)
{
if (tichests)
system.out.println("run:"+Thread.currentThread().getName()+"is saling ticket"+ tickets
--)//
}
}
}
使用Runnable接口创建多线程
*适合多了相同程序代码的线程去处理统一资源的情况,把虚拟cpu(线程)同程序的代码、数据有效分离
较好地体现了面向对象的设计思想
×可以避免由于Java单继承特性带来的局限。我们经常碰到这样一种情况。即当我们要将已经继承了某个类的子类放入多线程中。由于一个类不能同时有两个父类,所以不能用继承Thread类的方式,那么,这个类就只能采用实现Runnable
*当线程被构造时,需要的代码和数据通过一个对象作为构造函数实参传递进去,这个对象就是一个实现了Runnable接口的类的实例。
*事实上,几乎所有多线程应用都可用Runnable接口方式 -
lesson5-java
2008-06-23 22:02:58
第五课
进程和线程
lesson.javaclass Threaddemo1
{
public static viod main(String [] args//main方法是在线程上进行的
{
new TestTread().run();
while(true)
{
system.out.println("main()"+Thread.currentThread().getName());//thread类静态方法,
返回一个线程类的对象,得到这个线程的名称
}
}
}
class TestTread
{
public void run()
{
while (true)
{
system.out.println("run:"+Thread.currentThread().getName());//thread类静态方法,
返回一个线程类的对象,得到这个线程的名称
}
}
}执行后,run方法是无限循环,所以main后面的代码没有执行,这是单线程的
如果想实现多线程
class Threaddemo1
{
public static viod main(String [] args//main方法是在线程上进行的
{
new Thread().start();启用一个线程,开始执行他的程序代码及run()程序中的代码,但是Thread中的run()方法是一个空的函数没有任何意义,所以要编写一个子类覆盖他的run()方法;
new TestTread().start();//不同,调用Thread的start()方法启用线程开始执行他的程序代码;
while(true)
{
system.out.println("main()"+Thread.currentThread().getName())//thread类静态方法,
返回一个线程类的对象,得到这个线程的名称
}
}
}
class TestTread extend Thread//不同
{
public void run()
{
while (true)
{
system.out.println("run:"+Thread.currentThread().getName())//thread类静态方法,
返回一个线程类的对象,得到这个线程的名称
}
}
}二、用Thread类创建线程
*要将一段代码在一个新的线程上运行,该代码应该在一个类的run函数中,并且run函数所在的类是Thread类的子类,倒过来看,我们要实现多线程,必须编写一个继承了Tread类的子类,子类要覆盖Thread类中的run函数,在子类的run函数中调用想在新线程上运行的程序代码。
*启动一个新的线程,我们不是直接调用Thread的子类对象的run方法,而是调用Thread子类对象的start(从Thread类的继承到的)方法,Thread类对象的start方法将产生一个新的线程,并在该线程上运行该Thread类对象中的run方法,根据面向对象的运行时的多态性,在该线程上实际运行的是Thread子类(也就是我们写的那个类)对象的run方法
*由于线程的代码段在run方法中,那么该方法执行完成以后线程也就是相应的结束了,因而我们可以通过控制run方法中的循环的条件控制线程的结束。
三、后台线程和联合线程
*如果我们对某个线程对象在启用(调用start方法)之前调用了setDaemon(true)方法,这个线程就变成了后台线程
*对java程序来说,只要还有一个前台线程运行,这个进程就不会结束,如果一个进程中只有后台线程运行,这个进程就会结束。
*pp.join()的作用是吧pp所对应的线程合并到调用pp.jion();语句的线程中
后台例子:
class Threaddemo1
{
public static viod main(String [] args//main方法是在线程上进行的
{
Tread tt=new TestTread();
tt.setDaemon(true);
tt.start();
}
}
class TestTread extend Thread//不同
{
public void run()
{
while (true)
{
system.out.println("run:"+Thread.currentThread().getName())//
}
}
}
联合例子:
class Threaddemo1
{
public static viod main(String [] args//main方法是在线程上进行的
{
Tread tt=new TestTread();tt.start();
int index=0;
}
}
class TestTread extend Thread//不同
{
public void run()
{
while (true)
{
if(index++==100)
try{tt.join();}catch{Exception e}
system.out.println("run:"+Thread.currentThread().getName())//
}
}
} -
Java入门:一些JAVA相关的基础知识
2008-02-18 12:16:06
Java入门:一些JAVA相关的基础知识
JAVA相关基础知识
1、面向对象的特征有哪些方面
1.抽象:
抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节。抽象包括两个方面,一是过程抽象,二是数据抽象。
2.继承:
继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法。对象的一个新类可以从现有的类中派生,这个过程称为类继承。新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类)。派生类可以从它的基类那里继承方法和实例变量,并且类可以修改或增加新的方法使之更适合特殊的需要。
3.封装:
封装是把过程和数据包围起来,对数据的访问只能通过已定义的界面。面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。
4. 多态性:
多态性是指允许不同类的对象对同一消息作出响应。多态性包括参数化多态性和包含多态性。多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好的解决了应用程序函数同名问题。
2、String是最基本的数据类型吗?
基本数据类型包括byte、int、char、long、float、double、boolean和short。
java.lang.String类是final类型的,因此不可以继承这个类、不能修改这个类。为了提高效率节省空间,我们应该用StringBuffer类
3、int 和 Integer 有什么区别
Java 提供两种不同的类型:引用类型和原始类型(或内置类型)。Int是java的原始数据类型,Integer是java为int提供的封装类。Java为每个原始类型提供了封装类。
原始类型封装类
booleanBoolean
charCharacter
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
引用类型和原始类型的行为完全不同,并且它们具有不同的语义。引用类型和原始类型具有不同的特征和用法,它们包括:大小和速度问题,这种类型以哪种类型的数据结构存储,当引用类型和原始类型用作某个类的实例数据时所指定的缺省值。对象引用实例变量的缺省值为 null,而原始类型实例变量的缺省值与它们的类型有关。
4、String 和StringBuffer的区别
JAVA平台提供了两个类:String和StringBuffer,它们可以储存和操作字符串,即包含多个字符的字符数据。这个String类提供了数值不可改变的字符串。而这个StringBuffer类提供的字符串进行修改。当你知道字符数据要改变的时候你就可以使用StringBuffer。典型地,你可以使用StringBuffers来动态构造字符数据。
5、运行时异常与一般异常有何异同?
异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误。java编译器要求方法必须声明抛出可能发生的非运行时异常,但是并不要求必须声明抛出未被捕获的运行时异常。
6、说出Servlet的生命周期,并说出Servlet和CGI的区别。
Servlet被服务器实例化后,容器运行其init方法,请求到达时运行其service方法,service方法自动派遣运行与请求对应的doXXX方法(doGet,doPost)等,当服务器决定将实例销毁的时候调用其destroy方法。
与cgi的区别在于servlet处于服务器进程中,它通过多线程方式运行其service方法,一个实例可以服务于多个请求,并且其实例一般不会销毁,而CGI对每个请求都产生新的进程,服务完成后就销毁,所以效率上低于servlet。
7、说出ArrayList,Vector, LinkedList的存储性能和特性
ArrayList和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector由于使用了synchronized方法(线程安全),通常性能上较ArrayList差,而LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。
8、EJB是基于哪些技术实现的?并说出SessionBean和EntityBean的区别,StatefulBean和StatelessBean的区别。
EJB包括Session Bean、Entity Bean、Message Driven Bean,基于JNDI、RMI、JAT等技术实现。
SessionBean在J2EE应用程序中被用来完成一些服务器端的业务操作,例如访问数据库、调用其他EJB组件。EntityBean被用来代表应用系统中用到的数据。
对于客户机,SessionBean是一种非持久性对象,它实现某些在服务器上运行的业务逻辑。
对于客户机,EntityBean是一种持久性对象,它代表一个存储在持久性存储器中的实体的对象视图,或是一个由现有企业应用程序实现的实体。
Session Bean 还可以再细分为 Stateful Session Bean 与 Stateless Session Bean ,这两种的 Session Bean都可以将系统逻辑放在 method之中执行,不同的是 Stateful Session Bean 可以记录呼叫者的状态,因此通常来说,一个使用者会有一个相对应的 Stateful Session Bean 的实体。Stateless Session Bean 虽然也是逻辑组件,但是他却不负责记录使用者状态,也就是说当使用者呼叫 Stateless Session Bean 的时候,EJB Container 并不会找寻特定的 Stateless Session Bean 的实体来执行这个 method。换言之,很可能数个使用者在执行某个 Stateless Session Bean 的 methods 时,会是同一个 Bean 的 Instance 在执行。从内存方面来看, Stateful Session Bean 与 Stateless Session Bean 比较, Stateful Session Bean 会消耗 J2EE Server 较多的内存,然而 Stateful Session Bean 的优势却在于他可以维持使用者的状态。
9、Collection 和 Collections的区别。
Collection是集合类的上级接口,继承与他的接口主要有Set 和List.
Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。