一、线程的引入
如果说在操作系统中引入进程的目的是使多个程序并发执行以改善资源利用率及提高系统的吞吐量;那么在操作系统中再引入线程,则是为了减少程序并发执行时所付出的时空开销,使操作系统具有更好的并发性。
进程基本属性:进程是一个可拥有资源的独立单位;进程同时又是一个可以独立调度和分配的基本单位。
简而言之,进程是一个资源拥有者,因而在创建,撤销和切换中,系统必须付出为之较大的时空开销。在系统中所设置的进程不易过高,切换频率也不宜过高,但是这也就限制了并发程度的进一步提高。
如何使多个程序更好的并发执行,同时又尽量减少系统的开销-》线程:作为调度和分派的基本单位,不同时作为独立资源的单位,轻装运行。
二、创建方式
1.继承Thread:
定义Thread的子类,重写run()方法,run方法就代表线程需要完成的任务-线程执行体
创建Thread子类的实例,即创建线程对象
调用线程对象的start方法启动
public class MyThread extends Thread{
@Override
public void run{
System.out.println("MyThread");
}
}
public class Run{
public static void main(String[]args){
MyThread mythread=new MyThread();
mythread .start();
System.out.println("运行结束");
}
}
2实现Runnable接口
实现Runnable接口,重写run;创建Runnable实例,并将该实例作为参数传递到Thread中。
public class MyRunnable implements Runnable{
@Override
public void run(){
System.out.println("运行中");
}
}
public class Run{
public static void main(String[]args){
Runnable runnable=new MyRunnable();
runnable thread=new Thread(runnable);
thread.start();
System.out.println("运行结束!");
}
}
3使用Callable和Future创建线程:创建Callable接口的实现类,并重写call()方法,该方法就行线程方法执行体,且call()方法有执行返回值,再创建Callable实现类的实例;使用Future Task的实例,来包装Callable对象,即把callbale的实例以形参的方式传入FutureTask()的构造函数中;使用FutureTask对象作为Thread对象的target创建启动先线程;通过FutureTask实例对象调用get()方法得到子线程的返回值。
/*
*转
*/
public static class ThirdThreadCallable implements Callable<Integer>{
int i ;
//call()方法称之为线程方法执行体,且该方法有返回值,可通过FutureTask实例对象调用get()方法得到子线程的返回值
@Override
public Integer call() throws Exception {
for (; i <30; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
}
return i;
}
}
private static void createdThread3() {
//创建Callable对象
ThirdThreadCallable callable = new ThreadTest.ThirdThreadCallable();
//创建FutureTask对象,并把callable以形参的方式传入FutureTask的构造方法内
FutureTask<Integer> futureTask = new FutureTask<>(callable);
for (int i = 0; i < 30; i++) {
// 通过Thread类的currentThread方法可以得到当前的线程名
System.out.println(Thread.currentThread().getName()+" "+i);
if (i==20) {
//创建线程并启动
new Thread(futureTask, "有返回值的线程").start();
}
}
//获取子线程的返回值
try {
System.out.println("子线程的返回值: "+futureTask.get());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
三、对比
使用实现Runnable接口或Callable接口,同时还可以继承其他类
多个线程可以共享一个target对象,非常适合多个相同线程来处理同一资源的情况,从而将CPU,代码,数据分开,形成清晰的模型,较好的体现了面向对象的思想。
缺点:编程复杂,如果要访问当前线程,必须使用Thread.currentThread()方法。
使用继承Thread类:可以使用this访问当前线程,不可以继承其他类。