原文出处:http://www.iteye.com/topic/177641
进程:是一个程序在其自身地址空间的一次执行活动,进程是资源申请、调度和独立运行的单位,因此他使用系统中的运行资源;而程序不能申请系统资源,不能被系统调度,也不能作为独立运行的单位,因此它不占用系统的运行资源。
线程:是程序中的一个单一的连续控制流程,一个线程可以拥有多个线程 。记得刚学习 Java 的时候,对线程中的 run() 不知道是什么意思,现在大胆认为它就像 Java 的 main() 一样,可以理解为一个线程启动运行的入口函数。
创建一个线程的方式有两种,一种是继承 Thread 类,还有就是实现 Runnable 接口,两者都要重写 run() 方法。如下:
class MyThread extends Thread {
public void run(){}
} 或者
class MyThread implements Runnable{
public void run(){};
}
对了, Every thread has a priority. Threads with higher priority are executed in preference to threads with lower priority. 线程的静态变量 MAX_PRIORITY, MIN_PRIORITY, NORM_PRIORITY 其值分别是 10 , 1 , 5 不信自己打印出来看。我们创建一个线程默认的优先级是 5 ,我们在设置线程的优先级的范围显然是 1-10 。我们可以在多个线程同时运行的时候如何让操作系统将当前时间偏分给我们想要执行的线程时,可以将该线程的优先级设置 Thread.MAX_PRIORITY .
下面是一个生产者和消费者的多线程的例子:其规则很简单,只有生产出来东西才能有东西来消费。知识点:线程的创建、线程的同步、顺便回顾一下大学的操作系统。
class Test {
public static void main(String[] args) {
Queue q = new Queue();
Producer p = new Producer(q);
Consumer c = new Consumer(q);
p.start();
c.start();
}
}
class Producer extends Thread {
Queue q;
Producer(Queue q) {
this.q = q;
}
public void run() {
for (int i = 0; i < 10; i++) {
q.put(i);
System.out.println("Producer put " + i);
}
}
}
class Consumer extends Thread {
Queue q;
Consumer(Queue q) {
this.q = q;
}
public void run() {
while (true) {
System.out.println("Consumer get " + q.get());
}
}
}
class Queue {
int value;
boolean bFull = false;
public synchronized void put(int i) {
if (!bFull) {
value = i;
bFull = true;
notify();
}
try {
wait();
} catch (Exception e) {
e.printStackTrace();
}
}
public synchronized int get() {
if (!bFull) {
try {
wait();
} catch (Exception e) {
e.printStackTrace();
}
}
bFull = false;
notify();
return value;
}
}
上面的例子只是一个很普遍的例子,在 j2me 中的运用如:基于 c/s 结构的发送请求和接受请求响应就是一个运用很广泛的实列。
Java 多线程一个很重要的关键字就是线程同步 synchronized, 下面的火车票的售票系统的模型:同步分同步块和同步方法:
class SellThread implements Runnable
{
int tickets=100;
Object obj=new Object();
boolean b=false;
public void run()
{
if(b==false)
{
while(true)
sell();
}
else
{
while(true)
{
synchronized(obj)
{
try
{
Thread.sleep(10);
}
catch(Exception e)
{
e.printStackTrace();
}
synchronized(this)
{
if(tickets>0)
{
System.out.println("obj:"+Thread.currentThread().getName()+
" sell tickets:"+tickets);
tickets--;
}
}
}
}
}
}
public synchronized void sell()
{
synchronized(obj)
{
if(tickets>0)
{
try
{
Thread.sleep(10);
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println("sell():"+Thread.currentThread().getName()+
" sell tickets:"+tickets);
tickets--;
}
}
}
}
通过网上资料得知:同步块和同步方法其实本质是一样的:都是对对象枷锁。 Java 中每个对象都有一个监视器 ---- 锁,同步方法是利用 this 所代表的对象的锁,同步块利用的是同步块对象本身的锁。
线程池: J 2ME 中没有像在 jdk 中的那样有现成(包 util.concurrent )的线程池直接调用即可,那就得自己写了,下面是编写线程池时值得参考的规则(来自 IBM 的 Brian Goetz 和 Quiotix Corp 总结 ):
- 不要对那些同步等待其它任务结果的任务排队。这可能会导致上面所描述的那种形式的死锁,在那种死锁中,所有线程都被一些任务所占用,这些任务依次等待排队任务的结果,而这些任务又无法执行,因为所有的线程都很忙。
- 在为时间可能很长的操作使用合用的线程时要小心。如果程序必须等待诸如 I/O 完成这样的某个资源,那么请指定最长的等待时间,以及随后是失效还是将任务重新排队以便稍后执行。这样做保证了:通过将某个线程释放给某个可能成功完成的任务,从而将最终取得 某些 进展。
- 理解任务。要有效地调整线程池大小,您需要理解正在排队的任务以及它们正在做什么。它们是 CPU 限制的( CPU-bound )吗?它们是 I/O 限制的( I/O-bound )吗?您的答案将影响您如何调整应用程序。如果您有不同的任务类,这些类有着截然不同的特征,那么为不同任务类设置多个工作队列可能会有意义,这样可以相应地调整每个池。
今天就这么多了,吃饭去啦。