什么是线程
要想知道什么是线程,就要知道什么是进程。那什么是进程呢?进程指的是操作系统中一个程序的执行生命周期,也就是从他点击run程序创建中,直到程序运行结束退出。整个执行过程叫做进程。
那什么是线程呢。一个进程中肯定不止有一个线程,那么通俗的将进程的每一个子任务就是一个线程。
对比进程和线程
1.与进程相比,线程更加的轻量级。线程的创建、撤销相比较于进程的开销要小的多。
2.没有进程就没有线程,也就是说一个进程终止,其中的线程必然也将终止。
3.进程的操作系统资源调度的基本到位。进程可以独享资源,线程是OS任务执行的基本单位,线程依托于进程的资源,无法独立申请操作系统中的资源。而一个进程中的所有线程共享所有资源。
Thread的命名
1.在创建线程时通过调用构造传参设置线程名称。
public Thread(String name);
public Thread(Runnable target,String name);
2.创建好了以后设置线程名称
public final synchronized void setName(String name);
3.获取当前线程
public static native Thread currentThread();//通过Thread.currentThread()来获取当前线程
4.获取线程名称
public final String getName();
用java实现多线程
用java实现多线程有三种方式。1.通过继承Thread类实现多线程。2.通过实现Runnable接口实现多线程。3.通过实现Callable接口实现多线程。
1.继承Thread类实现多线程
thread类是线程操作的核心类,新建一个线程的方式就是new Thread().start()启动。我们通过覆写Thread()类中的run()方法来规定这个线程的具体操作。
class MyThread extends Thread{
public MyThread(){
super();
}
public void run(){
for(int i=0;i<10;i++){
Ststem.out.print(i+" ");
}
}
}
public class Test{
public static void main(String[] args){
MyThread myThread = new MyThread();
myThread.start();
}
}
你是否好奇为什么我们明明覆写的是run方法,却要调用Thread的start()方法呢?因为一个线程的创建不是仅仅调用我们写的这几行run代码就可以了。后台实际上JVM调用start方法后。先判断当前的状态。状态正常,调用start()(JVM)的native本地方法。也就是说这个本地文件不是java写的而是底层的.c文件,通过这个文件来准备做一些资源的调度,系统分配的操作。然后回调run方法,继续执行。
如果没有通过start操作,直接调用run方法,没有了本地方法的操作。他就只是个普通方法而已了。
2.实现Runnable接口实现多线程
class MyThread implements Runnable{
public MyThread(){
super();
}
public void run(){
for(int i=0;i<10;i++){
Ststem.out.print(i+" ");
}
}
}
public class Test{
public static void main(String[] args){
MyThread myThread = new MyThread();
new Thread(muThread).start();
}
}
如果你通过Ctrl+B转到Thread类的具体实现,你可以发现Thread类也实现了Runnable接口。两个类公共实现一个接口,一个是我们真的要做的操作,一个是辅助我们实现。这就是典型的Java代理设计模型的思想啊。代理模式详解
实现Runable接口实现多线程的优点,我们通过new Thread创建对象,但是因为传递的实参都是一个我们MyThread实例化对象。也就说说回调的是同一个run方法。这样可以更好的描述共享资源的概念不是吗。
3.实现Callable实现多线程
如果我们希望线程执行完后带回一个返回值那么我们就需要实现Callable来实现多线程了。
于上面两个不同
Callable存放在util包下,我们通过覆写Callable的 V call()方法来实现多线程。
首先我们必须先理清Callabe和Thread的关系,因为每个线程都是通过Threadnew出来的。Callable可以作为FutureTask构造方法的参数类似于Runnable和Thread的关系,然后FutureTask实现了Runnable也就是说FutureTask可以作为Thread构造的参数。从而start->run->call方法实现我们定义的线程。我们通过task的get方法获取该线程的返回值。
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
class MyCallable implements Callable<String>{
private Integer ticket=10;
@Override
public String call() {
for(int i=0;i<10;i++){
try {
Thread.sleep(200);
}catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread()+":"+ticket--);
}
return "卖完了";
}
}
public class Test{
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<String> task = new FutureTask<>(new MyCallable());
new Thread(task).start();
System.out.println(task.get());
}
}