1.什么是线程
进程是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,线程则是进程的一个执行路径,一个进程中至少有一个线程,进程中的多个线程共享进程的资源。
操作系统在分配资源时是把资源分配给进程的,但是CPU资源比较特殊,它是被分配到线程的,因为真正要占用CPU运行的是线程,所以也说线程是CPU分配的基本单位。
在Java中,当我们启动main函数时其实就启动了一个JVM的进程,而main函数所在的线程就是这个进程中的一个线程,也称主线程。
2.线程创建与运行
Java中有三种线程创建方式,分别为实现Runnable接口的run方法,继承Thread类并重写run的方法,使用FutureTask方式。
(1)继承Thread类的方式
public class testThread extends Thread {
private int count = 5;
private String name;
public testThread(String name){
this.name = name;
}
@Override
public void run(){
for (int i=0;i<5;i++){
System.out.println(name + "运行 count= " +count--);
try {
sleep((int) Math.random() * 10);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
public static void main(String[] args) {
testThread mTh1 = new testThread("A");
testThread mTh2 = new testThread("B");
mTh1.start();
mTh2.start();
}
}
在main函数里面创建了一个MyThread的实例,然后调用该实例的start方法启动了线程。需要注意的是,当创建完thread对象后该线程并没有被启动执行,直到调用了start方法后才真正启动了线程。
其实调用start方法后线程并没有马上执行而是处于就绪状态,这个就绪状态是指该线程已经获取了除CPU资源外的其他资源,等待获取CPU资源后才会真正处于运行状态。一旦run方法执行完毕,该线程就处于终止状态。
使用继承方式的好处是,在run()方法内获取当前线程直接使用this就可以了,无须使用Thread.currentThread()方法;不好的地方是Java不支持多继承,如果继承了Thread类,那么就不能再继承其他类。另外任务与代码没有分离,当多个线程执行一样的任务时需要多份任务代码,而Runable则没有这个限制。
(2)实现Runnable接口的run方法
public class testRunnable implements Runnable {
private int count = 15;
@Override
public void run() {
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+"运行 count= " + count--);
try{
Thread.sleep((int)Math.random()*10);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
public static void main(String[] args) {
testRunnable mTh = new testRunnable();
new Thread(mTh,"C").start();
new Thread(mTh,"D").start();
new Thread(mTh,"E").start();
}
}
Thread和Runnable两者还有一个区别是如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易实现资源共享。链接:https://blog.csdn.net/u010926964/article/details/74962673
上面两种创建线程的方式有一个缺点,就是任务没有返回值,使用FutureTask方式则有
(3)使用FutureTask方式
public class CallerTask implements Callable<String> {
@Override
public String call() throws Exception {
return "hello";
}
public static void main(String[] args)throws InterruptedException {
FutureTask<String> futureTask = new FutureTask<>(new CallerTask());
new Thread(futureTask).start();
try{
String result = futureTask.get();
System.out.println(result);
}catch (ExecutionException e){
e.printStackTrace();
}
}
}