15.2 一个简单的多线程例子
下面是一个多线程的例子:
public class Test extends Thread{ private static int num=0; public static void main(String args[]){ for(int i=0;i < 100;i++){ Test t=new Test(); t.start(); } } @Override public void run(){ System.out.println(num); try{ Thread.sleep(1); } catch(InterruptedException e){ e.printStackTrace(); } num++; }}
解释一下上面的代码:
1.Test继承Thread,代表这个类可启动多线程
2.run方法是开启一个新的线程,但不能调用run,要用start才会启动一个新的线程。上面第6行代码的t.start(),会调用到run方法。
3.类的i是一个静态变量,所有对象共享。
4.main函数发起100个循环,每次循环都创建一个新的线程,然后启动(调用start)
5.每个线程启动只执行两行代码,打印i,给i加1。第12到17行代码是增加一个1毫秒的延迟(目的是为了让多线程效果更明显)
运行这段代码,会发现,它每次的结果都不一样。
有可能是 0、1、2、3、4、5、6……“正确”地到达100
也有可能是0、0、0、3、3……
也有可能是0、1、0、3、4……
机器性能越好,就越可能是第一种按顺序打印。(如果机器性能太强,每次打印都是第一种,那么可以调高上面的第13行代码里面的延迟值1)。
这到底是怎么回事呢?
因为所有线程都运行这个run,上一个线程没有运行完run,下一个线程可能已经开始,这样就可能打印到同一个i值,而i的值是所有线程都共享的,所以会出现上面的情形。
另外,还有一个函数式接口Runnable ,它只有一个方法run,事实上类Thread就实现了这个接口。这是上面的例子的lambda的写法,区别是Test不再继承Thread而是一个普通类:
public class Test{ private static int num=0; public static void main(String args[]){ for(int i=0;i < 100;i++){ Test t=new Test(); Runnable r=()-> { t.add(); }; Thread th=new Thread(r); th.start(); } } public void add(){ System.out.println(num); num++; }}
用lambda表达式会更简便一些。