前面有篇博文是小结c#的多线程的 http://www.cnblogs.com/sylvanas2012/archive/2012/07/26/2610591.html
java有点不同,实现多线程有两种方式:继承类Thread, 和 实现接口Runnable。
thread类有一个run函数,它是线程的入口,当启动一个新线程是,就从这个函数开始执行;
public class ThreadTest extends Thread{ public void run() { for (int i=0;i<5;i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" "+i); } } public static void main(String[] args) { ThreadTest test1 = new ThreadTest(); ThreadTest test2 = new ThreadTest(); test1.start(); test2.start(); } }
注意线程是调用start()来开始的。
Runnable有一点点不同,实现这个类的时候和Thread一样,但是创建线程的时候还是放入一个Thread中创建:
public class RunnableTest implements Runnable { private int cnt; public RunnableTest(int n) { super(); cnt = n; } public void run() { for (int i=0;i<5;i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" "+i+" "+--cnt); } } public static void main(String[] args) { RunnableTest t = new RunnableTest(10); Thread ta = new Thread(t); Thread tb = new Thread(t); ta.start(); tb.start(); } }
Thread和Runnable基本用法都是差不多的,但是从上面的例子可以看出,Runnable比较方便进程间数据的共享(公用了一个cnt计量单位),所以一样都使用Runnable。
线程常用的几个函数:
join(): 强制等待线程执行完毕。 例如如果在主线程里面加一句ta.join(),那么主线程会一直等待ta执行返回才接着执行后面的代码。但是在join之前已经创建的其他线程,则不会受影响,继续执行。
interrupt(): 挺有意思的一个函数,如果线程在执行sleep()函数 ,则打断它(以让sleep()函数抛出一个异常的方式中断),执行后面的语句。
setDaemon(true):设置为守护进程。守护进程的优先级是最低的,如果一个程序只剩下守护进程,那么它就中断所有守护进程而退出。 最常见的情况是,如果创建的全部是守护进程,那么当主函数main执行完毕后,就立刻终止所有线程而退出。
synchronized同步符号用法: 保证同一时刻,某段代码只有一个线程在执行。
wait()和notify(),notifyAll():让线程等待/唤醒。这两个函数比较奇怪,目前我不是很熟练,要配合synchronized符号使用,请看下面这个生产者-消费者例子(网上直接贴来的,写的挺好的):
public class tt { public static void main(String[] args) { Storage s = new Storage(); Producer p = new Producer(s); Consumer c = new Consumer(s); Thread tp = new Thread(p); Thread tc = new Thread(c); tp.start(); tc.start(); } } class Consumer implements Runnable {//消费者 Storage s = null; public Consumer(Storage s){ this.s = s; } public void run() { for(int i=0; i<20; i++){ Product p = s.pop();//取出产品 try { Thread.sleep((int)(Math.random()*1500)); } catch (InterruptedException e) { e.printStackTrace(); } } } } class Producer implements Runnable {//生产者 Storage s = null; public Producer(Storage s){ this.s = s; } public void run() { for(int i=0; i<20; i++){ Product p = new Product(i); s.push(p); //放入产品 // System.out.println("生产者放入:" + p); try { Thread.sleep((int)(Math.random()*1500)); } catch (InterruptedException e) { e.printStackTrace(); } } } } class Product { int id; public Product(int id){ this.id = id; } public String toString(){//重写toString方法 return "产品:"+this.id; } } class Storage { int index = 0; Product[] products = new Product[5]; public synchronized void push(Product p){//放入 while(index==this.products.length){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.products[index] = p; System.out.println("生产者放入"+index+"位置:" + p); index++; this.notifyAll(); } public synchronized Product pop(){//取出 while(this.index==0){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } index--; this.notifyAll(); System.out.println("消费者从"+ index+ "位置取出:" + this.products[index]); return this.products[index]; } }
大致流程:生产者每次产生一个产品,消费者一次消费一个产品; 仓库容量有限,当满存的时候,生产者就需要等待,直到有消费者消费,才被唤醒; 如果仓库是空的,那么消费者就不能消费,要等待,知道生产者生产出一个产品,并唤醒消费者。