早期很多绑定unix的ftp服务器和第三方ftp服务器,都会为每个连接创建(fork)一个新的进程。100个并发用户意味着要处理100个额外进程。由于进程是重量级的,太多进程会让服务器吃不消。
早期web服务器也有这个问题,不过http连接的短暂性而掩盖了一些。当使用增长时,web服务器的性能仍会下降。
这个问题的方案有两个:
1、使用数据库连接池或者进程池或者线程池的作用是?
没有池,每一个请求需要创建一次链接,使用完进行销毁。
创建池后,池内有一定数量的池连接。入站请求放入队列。每个进程从队列中删除一个请求,为这个请求提供服务。作用是:减少创建和销毁的过程,提升效率。大概300条进程池能完成相当于1000条进程默认的任务。(大概3倍)
2、线程与进程
一个进程包含多个线程。
每个进程在不同的内存区域。所以开销比较大,占用资源多。
每个线程使用相同的内存区域。所以开销比较小,占用资源少。
所以使用线程代替进程,可以让你的服务器性能提高3倍。使用可重用的线程池(不是可重用的进程池),服务器可以运行9倍快。
这种性能的提升给程序员开发带来了复杂性,因为线程共享内存所以使用时会产生对另一个线程数据结构的改变。因此有时需要线程同步,确保线程安全性和生命周期。如果一个程序中没有内存保护机制的操作系统(如mac os9,windows 95)中运行,也会以类是的方式破坏整个系统。
还有一种解决方案 也是效率最高的,适用java1.4及以后的版本。利用选择器(selector)
具体什么情况下使用线程:例如,计算多个文件的安全散列算法(SHA),这个程序是受限于I/O的,既程序的速度会受到从磁盘上读取文件所花费时间的限制。或者网络程序,程序运行的速度要比网络提供输入的速度快,因此很多阻塞的时间久白白耗费了。这些时间本可以被其他线程所用。
-------------
servlet是单实列,多线程。规范规定通常容器对单个jvm只建立一个servlet实例。
1.对于一个servlet,每个用户请求将生成新的线程。
2.当首次创建servlet时就会调用init()方法,而并不是每个用户请求都调用该方法。
3.当每个用户请求servlet时,都会调用server方法
线程在run()方法开始,run()方法结束。
单线程程序在main()方法返回时退出。多线程程序在main()方法和所以非守护线程都返回时才退出。(守护线程会执行后台任务,如垃圾回收,并不阻止虚拟机退出)。
-------------
[b]线程的2种实现方法[/b]
1、继承Thread类
2、实现Runable接口
一般推荐第二种方法,没有充分的理由。可以节约一个继承。
并在run()方法里面实现具体内容。
线程run()方法是固定的,所以无法向其传入参数或从中返回值。
传递参数:最简单的的方法是向构造函数传递参数。
返回参数:使用回调。
在线程类中,最后的位置,使用静态方法,或传过来的对象的实例方法回调。
[b]同步[/b]
只要是多线程共享资源或代码,都必须考虑同步。
使用关键字synchronized来实现同步块或者同步方法。
[b]同步的替代方法[/b]
对于线程调度引起的不一致行为问题,同步并不总是最好的解决方案。还有很多技术可以完全避免使用同步。
1、在任何可能的情况下,使用局部变量代替字段,局部变量没有同步问题。
java通过值而不是引用来传递参数。
String参数是安全的,因为它们是不可变的,final类型。StringBuffer参数是不安全的,因为它们不是不可变的,可以在创建后加以修改。
2、在自己的类中利用不可变性。要使一个对象不可变,只要将其所以字段声明为私有,不要编写任何可以改变它们的方法就行了。核心java库中有很多类是不可变的:如String,Integer等
3、只将非现场安全的类作用线程安全的类的一个私有字段。只要包含类仅以线程安全的方式访问此非安全类,并且只要永远不让这个私有字段的引用泄露到另一个对象中,那么这个类就是安全的。
[b]死锁[/b]
同步会导致另一个可能的问题:死锁。
写完论文需要看图书馆A,B两本书。张去图书馆借了A书,想借B书发现被李借走了。李也要写论文,想借A书,发现被张借走了。此时他们互不相让,就发送死锁。
解决办法是:让程序顺序访问。既是借书,必须先借A再借B。
[b]线程调度[/b]
优先级
java中,10是最高优先级,1是最低。默认为5.
设置优先级通过以下方法:
public final void setPriority(int newPriority)
在线程启动前调用:
t.setPriority(8);
t.start();
一般尽量使用太高优先级,避免其他线程遭受"饥饿"之苦。
早期web服务器也有这个问题,不过http连接的短暂性而掩盖了一些。当使用增长时,web服务器的性能仍会下降。
这个问题的方案有两个:
1、使用数据库连接池或者进程池或者线程池的作用是?
没有池,每一个请求需要创建一次链接,使用完进行销毁。
创建池后,池内有一定数量的池连接。入站请求放入队列。每个进程从队列中删除一个请求,为这个请求提供服务。作用是:减少创建和销毁的过程,提升效率。大概300条进程池能完成相当于1000条进程默认的任务。(大概3倍)
2、线程与进程
一个进程包含多个线程。
每个进程在不同的内存区域。所以开销比较大,占用资源多。
每个线程使用相同的内存区域。所以开销比较小,占用资源少。
所以使用线程代替进程,可以让你的服务器性能提高3倍。使用可重用的线程池(不是可重用的进程池),服务器可以运行9倍快。
这种性能的提升给程序员开发带来了复杂性,因为线程共享内存所以使用时会产生对另一个线程数据结构的改变。因此有时需要线程同步,确保线程安全性和生命周期。如果一个程序中没有内存保护机制的操作系统(如mac os9,windows 95)中运行,也会以类是的方式破坏整个系统。
还有一种解决方案 也是效率最高的,适用java1.4及以后的版本。利用选择器(selector)
具体什么情况下使用线程:例如,计算多个文件的安全散列算法(SHA),这个程序是受限于I/O的,既程序的速度会受到从磁盘上读取文件所花费时间的限制。或者网络程序,程序运行的速度要比网络提供输入的速度快,因此很多阻塞的时间久白白耗费了。这些时间本可以被其他线程所用。
-------------
servlet是单实列,多线程。规范规定通常容器对单个jvm只建立一个servlet实例。
1.对于一个servlet,每个用户请求将生成新的线程。
2.当首次创建servlet时就会调用init()方法,而并不是每个用户请求都调用该方法。
3.当每个用户请求servlet时,都会调用server方法
线程在run()方法开始,run()方法结束。
单线程程序在main()方法返回时退出。多线程程序在main()方法和所以非守护线程都返回时才退出。(守护线程会执行后台任务,如垃圾回收,并不阻止虚拟机退出)。
-------------
[b]线程的2种实现方法[/b]
1、继承Thread类
2、实现Runable接口
一般推荐第二种方法,没有充分的理由。可以节约一个继承。
并在run()方法里面实现具体内容。
线程run()方法是固定的,所以无法向其传入参数或从中返回值。
传递参数:最简单的的方法是向构造函数传递参数。
返回参数:使用回调。
在线程类中,最后的位置,使用静态方法,或传过来的对象的实例方法回调。
[b]同步[/b]
只要是多线程共享资源或代码,都必须考虑同步。
使用关键字synchronized来实现同步块或者同步方法。
[b]同步的替代方法[/b]
对于线程调度引起的不一致行为问题,同步并不总是最好的解决方案。还有很多技术可以完全避免使用同步。
1、在任何可能的情况下,使用局部变量代替字段,局部变量没有同步问题。
java通过值而不是引用来传递参数。
String参数是安全的,因为它们是不可变的,final类型。StringBuffer参数是不安全的,因为它们不是不可变的,可以在创建后加以修改。
2、在自己的类中利用不可变性。要使一个对象不可变,只要将其所以字段声明为私有,不要编写任何可以改变它们的方法就行了。核心java库中有很多类是不可变的:如String,Integer等
3、只将非现场安全的类作用线程安全的类的一个私有字段。只要包含类仅以线程安全的方式访问此非安全类,并且只要永远不让这个私有字段的引用泄露到另一个对象中,那么这个类就是安全的。
[b]死锁[/b]
同步会导致另一个可能的问题:死锁。
写完论文需要看图书馆A,B两本书。张去图书馆借了A书,想借B书发现被李借走了。李也要写论文,想借A书,发现被张借走了。此时他们互不相让,就发送死锁。
解决办法是:让程序顺序访问。既是借书,必须先借A再借B。
[b]线程调度[/b]
优先级
java中,10是最高优先级,1是最低。默认为5.
设置优先级通过以下方法:
public final void setPriority(int newPriority)
在线程启动前调用:
t.setPriority(8);
t.start();
一般尽量使用太高优先级,避免其他线程遭受"饥饿"之苦。