从第一天学习JavaSE开始,接触的例子程序都是在
public static void main中运行的,这个方法是一个Java程序的入口,整个Java工程中只有一个类能拥有这个方法。在这个方法中运行的程序都是在主线程中跑的。从开始到程序结束,只有一条路径,只能走这一条路。多线程最简单的来说就是,为程序开辟多条运行的路径,即从开始到最后,有几条路同时运行,同时使用cpu资源。
程序并行技术是程序开发的难点,使用多线程需要保证线程安全,即在同一时刻,只能有一个类读写相同的资源。所以在线程中会出现“锁”的概念,数据库中也有多重多样的锁的技术,都是为程序的线程安全。作为一个初学者,建议少使用Java多线程开发应用程序,因为一不小心就会出现各种各样的问题,引发各种错误,而这种错误在有些行业会造成很可怕的后果。
线程也是一个接口或一个类,要使用它就要创建他的对象或他子类的对象,在传统线程技术中有两种创建线程的方式:
Thread类就是线程类,Thread t=new Thread(),这样创建了一个线程对象。开始执行线程需要调用它的start()方法。
查看JDK帮助文档:
文档中写的很清楚,线程的一些概况。Thread继承自Runnable接口。
可以看到Thread的构造方法,有很多,大概有个印象就行。
后面还有Thread的一些方法。得到线程名字、状态、打断、优先级、等待、睡眠等等操作。
Thread t=new Thread();
t.start();
这是Thread的源码,无参构造方法,可以看到里面调用了init()方法,继续追踪:
这个方法接受的参数:线程组,实现Runnable接口的对象,名字,堆大小。然后一大段代码初始化了这个Thread对象。
执行线程后运行的代码是run()方法中包含的:
@Override
public void run() {
if (target != null) {
target.run();
}
}
这是Thread类源码中的run,可以看到找了一个target的run,并没有做什么。要让线程帮我们做事,就需要让Thread的子类重写run():
Thread t=new Thread(){
@Override
public void run() {
while(true){
System.out.println("name : "+Thread.currentThread().getName());
}
}
};
t.start();
输出结果:
name : Thread-0
name : Thread-0
name : Thread-0
…………
无限输出。
把需要运行的代码放在run()方法中,就可以在子线程中运行了。
第二种创建线程的方式:
使用Runnable接口,之前已经看到Thread提供的构造方法了。不多说了,就直接上代码:
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getId());
System.out.println(Thread.currentThread().getName());
System.out.println(Thread.currentThread().getState());
System.out.println(Thread.currentThread().getPriority());
System.out.println(Thread.currentThread().getThreadGroup());
}
});
t.start();
输出结果:
9
Thread-0
RUNNABLE
5
java.lang.ThreadGroup[name=main,maxpri=10]
为什么要用包装一个Runnable对象,按照面向对象的思想,将要做的事情封装在一个类中,是更好设计。
Thread源码中,它的run()方法会判断target这个属性,如果不为空,就执行它的run。Target就是Runnable对象,我们传入的Runnable对象会在init中赋给target。所以……
追踪start()方法,发现调用了start0()这个native方法。
很多比较费时的操作需要放在子线程中,比如下载、网络、IO等操作。用好多线程并不能很好的提升程序的运行速度,只是开辟新的运行路径。