Java的多线程机制
1.利用Thread的子类创建线程
例1.用Thread子类创建多线程程序。
先定义一个Thread的子类,该类的run方法只用来输出一些信息。
package thread; public class myThread extends Thread{ private static int count=0; public void run() { int i; for(i=0;i<100;i++){ count=count+1; System.out.println("My name is "+getName()+" count="+count); try { sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public myThread(String name){ super(name); } }
下面用程序来创建线程对象并运行该线程对象。
package thread; public class mulThread { public static void main(String[] args) { myThread trFirst,trSecond; trFirst = new myThread("First Thread"); trSecond = new myThread("Second Thread"); trFirst.start(); trSecond.start(); System.out.println("主线程结束!"); } }
2.实现Runnable接口创建线程
例2. 继承Runnable接口实现多线程。
package thread; public class ThreadImRunable implements Runnable{ private static int count=0; private Thread t; public void run() { int i; for(i=0;i<100;i++){ count++; System.out.println("My name is "+t.getName()+" count="+count); try { t.sleep(10); } catch (Exception e) { // TODO: handle exception } } } public ThreadImRunable(String name){ t = new Thread(this,name); } public void start(){ t.start(); } }
主程序跟前面相同。
package thread; public class mulThread { public static void main(String[] args) { myThread trFirst,trSecond; trFirst = new myThread("First Thread"); trSecond = new myThread("Second Thread"); trFirst.start(); trSecond.start(); System.out.println("主线程结束!"); } }
3.使用isAlive()和join()等待子线程结束
例3. join()方法使用示例。
package thread; public class demoJoin { public static void main(String[] args){ myThread trFirst,trSecond; trFirst = new myThread("First Thread"); trSecond = new myThread("Second Thread"); try { trFirst.start(); trSecond.start(); trFirst.join(); trSecond.join(); } catch (InterruptedException e) { System.out.println("主线程被中断!"); } System.out.println("主线程结束!"); } }
4.设置线程优先级
例4. 设置线程优先级示例。
package thread; public class clicker extends Thread{ private int click=0; private volatile boolean running=true;//volatile告诉编译器,不要自作主张为它编译优化 public int getClick(){ return click; } public void run() { while(running){ click = click + 1; } } public void normalStop(){ running = false; } }
程序中的循环变量running被声明成volatile,这个关键字告诉编译器,不要自作主张为它进行编译优化。
注意:不要将循环体中“click=click+1”改成“++click”的形式。对于前者,编译器会生成多条命令,执行过程中系统有机会将它中断。而后者只有一条指令,系统不能将其中断,这样其他进程就难以有机会使用CPU。
package thread; public class demoPri { public static void main(String[] args) { clicker c1High,c2Low; c1High=new clicker(); c2Low=new clicker(); c1High.setPriority(Thread.NORM_PRIORITY+2); c2Low.setPriority(Thread.NORM_PRIORITY-2); c2Low.start(); c1High.start(); try { Thread.sleep(1000); } catch (InterruptedException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } c1High.normalStop(); c2Low.normalStop(); try { c1High.join(); c2Low.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("c1High执行循环的次数为:"+c1High.getClick()); System.out.println("c2Low 执行循环的次数为:"+c2Low.getClick()); } }
程序的输出结果为:
c1High执行循环的次数为:427835536
c2Low 执行循环的次数为:396647205
结果表明,优先级高的线程获得了更多的CPU运行时间。
5.线程的互斥
例5. 线程互斥示例。
package thread; public class mutixThread extends Thread{ private static int count = 0; private synchronized static void change(Thread t){ count = count + 1; System.out.println("My name is "+t.getName()+" count="+count); } public void run() { int i; for(i=0;i<100;i++){ change(this); try { sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public mutixThread(String name){ super(name); } }
下面写一个程序测试它的运行情况。
package thread; public class demoMutix { public static void main(String[] args){ mutixThread t1,t2,t3; t1 = new mutixThread("First Thread"); t2 = new mutixThread("Second Thread"); t3 = new mutixThread("Third Thread"); t1.start(); t2.start(); t3.start(); try { t1.join(); t2.join(); t3.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("主线程结束"); } }
程序运行结果如下:
..... My name is Third Thread count=297 My name is First Thread count=298 My name is Third Thread count=299 My name is Second Thread count=300 主线程结束
6.线程的同步
例6. 线程同步示例。
package thread; public class commSource { static boolean flag = true; static int data; static int count; }
package thread; public class setDataThread extends Thread { private readDataThread otherThread=null; //存储另外一个线程对象 public void run(){ for(int i=0;i<100;i++){ if(!commSource.flag) try { synchronized(this){ //锁定当前对象 wait(); //阻塞自己 } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } commSource.flag = false; commSource.data = (int)(Math.random()*1000); commSource.count++; System.out.println("设置数据:"+commSource.data+" count="+commSource.count); synchronized(otherThread){ //锁定另外一个线程对象 otherThread.notify(); //唤醒另外一个线程对象 } } } public void setOtherThread(readDataThread rt){ otherThread=rt; } }
package thread; public class readDataThread extends Thread{ private setDataThread otherThread = null; public void run(){ for(int i=0;i<100;i++){ if(commSource.flag) try { synchronized(this){ wait(); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } commSource.flag = true; System.out.println("获得数据:"+commSource.data); synchronized(otherThread){ otherThread.notify(); } } } public void setOtherThread(setDataThread st){ otherThread = st; } }
package thread; public class demoSynchorny { public static void main(String[] args) { setDataThread str; readDataThread rtr; str=new setDataThread(); rtr=new readDataThread(); str.setOtherThread(rtr); rtr.setOtherThread(str); str.start(); rtr.start(); } }
输出结果如下:
设置数据:295 count=1 获得数据:295 ...... 设置数据:974 count=99 获得数据:974 设置数据:526 count=100 获得数据:526
两个线程是严格交替运行的。
7.暂停恢复和停止线程
例7. 自己编写线程的暂停、恢复和停止方法。
package thread; public class enhanceThread extends Thread { private static final int STOP = 1; private static final int RUNNING = 2; private static final int SUSPEND = 3; private int state = STOP; public synchronized void run(){ int cnt = 0; while(state!=STOP){ if(state==SUSPEND){ try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } ++cnt; System.out.println("线程正在运行:"+cnt); try { sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public void normalStop(){ state = STOP; } public void normalSuspend(){ state = SUSPEND; } //恢复线程运行 public synchronized void normalResume(){ state = RUNNING; notify(); } public enhanceThread(){ state = RUNNING; } }
package thread; public class demoEhanceThread { public static void main(String[] args) { enhanceThread tr; tr = new enhanceThread(); System.out.println("启动线程!"); tr.start(); try { Thread.sleep(1000); System.out.println("将线程挂起!"); tr.normalSuspend(); Thread.sleep(1000); System.out.println("恢复线程运行!"); tr.normalResume(); Thread.sleep(1000); System.out.println("终止线程运行!"); tr.normalStop(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
输出结果如下:
启动线程! 线程正在运行:1 线程正在运行:2 线程正在运行:3 线程正在运行:4 线程正在运行:5 线程正在运行:6 线程正在运行:7 线程正在运行:8 线程正在运行:9 线程正在运行:10 将线程挂起! 恢复线程运行! 线程正在运行:11 线程正在运行:12 线程正在运行:13 线程正在运行:14 线程正在运行:15 线程正在运行:16 线程正在运行:17 线程正在运行:18 线程正在运行:19 线程正在运行:20 终止线程运行!
8.生产者-消费者问题实例
例8. 生产者-消费者实例。
package thread; public class common { private int production[]; //存放产品的缓冲区 private int count; //产品的实际数目 private int BUFFERSIZE = 6; //缓冲区大小 public common(){ production = new int[BUFFERSIZE]; count = 0; } //从缓冲区中取数据 public synchronized int get(){ int result; while(count<=0) try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } result = production[--count]; notifyAll(); return result; } //向缓冲区中写数据 public synchronized void put(int newproduct){ while(count>=BUFFERSIZE) try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } production[count++]=newproduct; notifyAll(); } }
package thread; //消费者线程 public class consumer extends Thread { private common comm; public consumer(common mycomm){ comm = mycomm; } public synchronized void run(){ //线程体 int i,production; for(i=1;i<=20;i++){ //消费线程计数 production = comm.get(); System.out.println("得到的数据为:"+production); try { sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
package thread; //生产者线程 public class producer extends Thread { private common comm; public producer(common mycomm){ comm = mycomm; } public synchronized void run(){ int i; for(i=1;i<=10;i++){ comm.put(i); System.out.println("生产的数据为:"+i); try { sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
package thread; public class producer_consumer { public static void main(String[] args){ common comm = new common(); producer p1 = new producer(comm); producer p2 = new producer(comm); consumer c1 = new consumer(comm); p1.start(); p2.start(); c1.start(); } }
程序某次运行结果如下:
生产的数据为:1 得到的数据为:1 生产的数据为:1 得到的数据为:2 生产的数据为:2 生产的数据为:2 生产的数据为:3 得到的数据为:3 生产的数据为:3 生产的数据为:4 得到的数据为:4 生产的数据为:4 生产的数据为:5 得到的数据为:5 生产的数据为:5 得到的数据为:5 生产的数据为:6 生产的数据为:6 得到的数据为:6 生产的数据为:7 生产的数据为:8 得到的数据为:7 得到的数据为:8 生产的数据为:9 生产的数据为:10 得到的数据为:9 得到的数据为:10 生产的数据为:7 得到的数据为:7 生产的数据为:8 得到的数据为:8 生产的数据为:9 得到的数据为:9 生产的数据为:10 得到的数据为:10 得到的数据为:6 得到的数据为:4 得到的数据为:3 得到的数据为:2 得到的数据为:1
结果表明,该程序已经很好地解决了生产者线程和消费者线程间的同步问题。