什么是线程
线程是进程中独立运行的子任务(进程是受操作系统管理的基本运行单元),在没有同步的情况下,线程的执行是随机乱序的。
在Java编程中,有四种方式去实现多线程。
一、实现Runnable接口
Runnable接口中只有一个抽象run()方法,这个方法是运行线程的入口,而不是启动线程的入口,启动线程用start()方法,实现这个接口的类就具有了多线程的功能了。
public class MyThread implements Runnable {
private String name;
public MyThread(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println("inner thread is running!");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
实现Runnable接口的类,需要使用Thread类的构造函数实例化一个线程,下面使用了带有线程名称的构造函数,第二个参数是线程名称。
public Thread(Runnable target, String name)
运行测试:
public static void main(String[] args) {
Thread thread = new Thread(new MyThread("mythread"),"mythread");
thread.start();
System.out.println(thread.getName());
System.out.println("main thread is running!" +Thread.currentThread().getName());
}
运行结果:
mythread
inner thread is running!
main thread is running!main
二、继承Thread类
其实继承Thread类实现多线程,本质上也是实现了Runnable接口,因为Thread类实现了Runnable接口。
public class MyThread extends Thread {
private String some;
public MyThread(String some) {
this.some = some;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" is running!"+"--"+getSome());
}
public String getSome() {
return some;
}
public void setSome(String some) {
this.some = some;
}
}
实现Thread类,在实例化一个线程时,只需要实例化该类。
public static void main(String[] args) {
MyThread thread = new MyThread("mythread");
thread.start();
System.out.println(Thread.currentThread().getName()+" thread is running!" );
}
运行结果:
main thread is running!
Thread-0 is running!--mythread
三、继承TimerTask类
由于TimerTask实现了Runnable接口,因此继承TimerTask也能够实现多线程。用这种方法,有两种方式启动线程。
- 使用定时器Timer的调度方法schedule()。
- 使用Thread的构造函数。
private static Timer timer = new Timer();
public static class Mytask extends TimerTask{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" is running!");
}
}
public static void main(String[] args) {
//第一种启动方法
Mytask mytask = new Mytask();
timer.schedule(mytask, 1000L);
//第二种启动方法
Thread thread = new Thread(mytask,"mytask");
thread.start();
}
运行结果:
mytask is running!
Timer-0 is running!
四、实现Callable接口
Callable接口中只有一个call()方法,该方法具有返回值,并且可以抛出异常。和Runnable接口有很大的区别,是一种更加高级的实现。
public class CallableService<T> implements Callable<T> {
private int age;
public CallableService(int age) {
super();
this.age=age;
}
@Override
public T call() throws Exception {
System.out.println(Thread.currentThread().getName()+" is running!");
return (T) ("返回值是:"+age);
}
}
启动该线程,只需要实例化实现Callable接口的类,然后调用call()方法。
运行测试:
public static void main(String[] args) throws Exception {
CallableService<String> service = new CallableService<String>(100);
String t = service.call();
}
测试结果:
返回值是:100
Callable可以结合Future使用,能够实现更多的功能。这个在后续的博客中会讲到。
线程的状态
- 初始化状态:即线程的新生状态,使用new出来的线程。
- 运行状态:在线程调用start()方法后,且没有发生任何意外和认为的中断,此时线程处于运行状态。
- 阻塞状态:线程调用wait(),sleep(),suepend()方法后,将处于该状态。
销毁状态:线程自然的运行结束或调用stop()方法销毁线程。
这个图不是最完善的,在暂停状态时,当有线程调用notify()或notifyAll()方法时,阻塞的线程会抢占监视器,先得到监视器的线程先执行。