线程篇(一):Java中的线程(基础)

时间:2023-01-18 21:11:53

线程和进程的概念

几乎所有的操作系统都支持进程的概念,所有运行中的任务通常对应一个进程(Process)。当一个程序进入内存运行时,即变成一个进程。进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位。 多线程则扩展了多进程的概念,使得同一个进程可以同时并发处理多个任务。线程(Thread)也被称作轻量级进程(Lightweight Process),线程是进程的执行单元。就像进程在操作系统中的地位一样,线程在程序中是独立的、并发的执行流。当进程被初始化后,主线程就被创建了。对于绝大多数的应用程序来说,通常仅要求有一个主线程,但也可以在该进程内创建多条顺序执行流,这些顺序执行流就是线程,每个线程也是相互独立的。 线程是进程的组成部分,一个进程可以拥有多个线程,一个线程必须有一个父进程。线程可以拥有自己的堆栈、自己的程序计数器和自己的局域变量,但不拥有系统资源,它与父进程的其他线程共享该进程所拥有的全部资源。因为多个线程共享父进程里的全部资源,因此编程更加方便;但必须更加小心,因为需要确保线程不会妨碍同一进程里的其他线程。

线程的创建和启动

JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。

1.继承Thread类创建线程类

用一个子类继承Thread,然后在类中重写run()方法,这个run()方法就是线程要执行的任务。然后再创建这个子类的对象,调用他的start()方法即可开启该线程。示例如下:
public class FirstThread extends Thread{

@Override
public void run()
{
for (int i = 0; i < 10 ;i++)
{
System.out.println(this.currentThread()+" num:"+i);
}
}

public static void main(String[] args){
FirstThread thread_0 = new FirstThread();
FirstThread thread_1 = new FirstThread();
thread_0.start();
thread_1.start();
}
}
两个线程会随机分配内存运行空间,所以运行结果也是随机值,其中一次运行结果如下,我们可以看到两个线程是交替执行的。
Thread[Thread-0,5,main] num:0
Thread[Thread-0,5,main] num:1
Thread[Thread-1,5,main] num:0
Thread[Thread-0,5,main] num:2
Thread[Thread-0,5,main] num:3
Thread[Thread-1,5,main] num:1
Thread[Thread-1,5,main] num:2
Thread[Thread-1,5,main] num:3
Thread[Thread-0,5,main] num:4
Thread[Thread-0,5,main] num:5
Thread[Thread-0,5,main] num:6
Thread[Thread-1,5,main] num:4
Thread[Thread-0,5,main] num:7
Thread[Thread-0,5,main] num:8
Thread[Thread-0,5,main] num:9
Thread[Thread-1,5,main] num:5
Thread[Thread-1,5,main] num:6
Thread[Thread-1,5,main] num:7
Thread[Thread-1,5,main] num:8
Thread[Thread-1,5,main] num:9

2.实现Runnable接口创建子线程

首先定义一个实现Runnable接口的类,重写run()方法,与上一个实现方式相同,run()方法是该线程的执行体。再创建该类的实例,用这个实例作为target来创建Thread对象,用Thread对象调用start()方法,即可开启线程。代码如下所示:
public class SecondThread implements Runnable{

@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread() +" num:"+i);
}
}
public static void main(String[] args){
SecondThread thread_0 = new SecondThread();
SecondThread thread_1 = new SecondThread();
new Thread(thread_0).start();
new Thread(thread_1).start();
}
}
与线程的第一个实现方式不同,SecondThread只能作为Thread的target,才能执行线程。运行结果如下:
Thread[Thread-0,5,main] num:0
Thread[Thread-0,5,main] num:1
Thread[Thread-1,5,main] num:0
Thread[Thread-1,5,main] num:1
Thread[Thread-1,5,main] num:2
Thread[Thread-1,5,main] num:3
Thread[Thread-1,5,main] num:4
Thread[Thread-1,5,main] num:5
Thread[Thread-1,5,main] num:6
Thread[Thread-0,5,main] num:2
Thread[Thread-1,5,main] num:7
Thread[Thread-0,5,main] num:3
Thread[Thread-0,5,main] num:4
Thread[Thread-1,5,main] num:8
Thread[Thread-0,5,main] num:5
Thread[Thread-0,5,main] num:6
Thread[Thread-0,5,main] num:7
Thread[Thread-0,5,main] num:8
Thread[Thread-1,5,main] num:9
Thread[Thread-0,5,main] num:9

3.使用Callable和Future创建有返回值的线程

使用Callable和Future我们可以创建一个带有返回值的线程,我们基本上很少使用这种方式。在Android中更是很少,因为在获取子线程的返回值的时候,会阻塞当前线程,违反我们使用线程的目的。下面我们来说一下这种线程的使用方式,分以下几个步骤:1、创建一个Callable的实现类,并实现它的call()方法。
2、用FutureTask来包装Callable对象,创建FutureTask的对象task。3、把FutureTask对象task作为Thread的target,创建一个Thread对象,并开启线程。4、用task.get()获取子线程的返回值。注意调用该方法时,会阻塞当前线程,直到获取到子线程的返回值。
public class ThirdThread {
public static void main(String[] args)
{

FutureTask<Integer> task = new FutureTask<Integer>(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int i = 0;
for (;i<10;i++)
{
System.out.println(Thread.currentThread() + " num:"+i);
}
return i;
}
});
Thread thread = new Thread(task);
thread.start();

for (int j = 0;j < 10; j++)
{
System.out.println(Thread.currentThread() + " num:"+j);
}

try {
System.out.println("子线程的返回值:" + task.get());
} catch (Exception e) {
System.out.println("错误的提示e" + e);
}
}
}
打印结果如下:
Thread[main,5,main] num:0
Thread[main,5,main] num:1
Thread[main,5,main] num:2
Thread[main,5,main] num:3
Thread[main,5,main] num:4
Thread[Thread-0,5,main] num:0
Thread[Thread-0,5,main] num:1
Thread[main,5,main] num:5
Thread[Thread-0,5,main] num:2
Thread[Thread-0,5,main] num:3
Thread[Thread-0,5,main] num:4
Thread[Thread-0,5,main] num:5
Thread[Thread-0,5,main] num:6
Thread[Thread-0,5,main] num:7
Thread[Thread-0,5,main] num:8
Thread[Thread-0,5,main] num:9
Thread[main,5,main] num:6
Thread[main,5,main] num:7
Thread[main,5,main] num:8
Thread[main,5,main] num:9
子线程的返回值:10
其中Thread[main,5,main]代表的是主线程,java程序在进入main()方法的时候,就已经创建的一个线程,这个线程就是主线程。获取子线程的返回值的方法需要使用try-catch包裹。
以上是三种线程的基本使用方式。该篇为Java的线程基础篇,只是为Android线程入门。所以更深的Java线程知识,之后再补充。