螺竹编程
发布于 2024-05-17 / 4 阅读
1

Java并发编程/线程基础:线程详解

线程的属性

id和名字

每个线程都有一个id和name。id是一个递增的整数,每创建一个线程就加一。name的默认值是Thread-[编号],name可以在Thread的构造方法中进行指定,也可以通过setName方法进行设置。

优先级

线程有优先级的概念,在Java中,优先级从1到10,默认为5。这个优先级会被映射到操作系统中线程的优先级,不过不同的操作系统各不相同(比如有的操作系统不具有10个优先级),Java中不同的优先级可能会被映射到操作系统中相同的优先级。另外,优先级对操作系统而言主要是一种建议和提示,而非强制。所以,在编程中不要过于依赖优先级。

java中设置线程优先级的方法:public final void setPriority(int priority)。java中获取线程的优先级的方法为:public final int getPriority()

状态

线程的生命周期分为新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)这 5种状态。在系统运行过程中不断有新的线程被创建, 旧的线程在执行完毕后被清理,线程在排队获取共享资源或者锁时将被阻塞,因此运行中的线程会在就绪、阻塞、运行状态之间来回切换。

线程的创建

继承Thread类

Thread类实现了Runnable接口并定义了操作线程的一些方法,我们可以通过继承Thread类的方式创建一个线程。具体实现为创建一个类并继承Thread接口,然后实例化线程对象并调用start方法启动线程。start方法是一个native方法,通过在操作系统上启动一个新线程,并最终执行run方法来启动一个线程。run方法内的代码是线程类的具体实现逻辑。具体的实现代码如下:

//step 1:通过继承 Thread类创建NewThread 线程
public class NewThread extends Thread{
	public void run(){
		System.out.println("create a thread by extends Thread");
    }
}
//step 2:实例化一个NewThread线程对象
NewThread newThread=new NewThread();
//step 3:调用start 方法启动NewThread 线程
newThread.start();

以上代码定义了一个名为NewThread的线程类,该类继承了Thread,run方法内的代码为线程的具体执行逻辑,在使用该线程时只需新建一个该线程的对象并调用其start方法即可。

实现Runnable接口

    基于Java编程语言的规范,如果子类已经继承了一个类,就无法再直接继承Thread类,此时可以通过实现Runnable接口创建线程。具体的实现过程为:通过实现Runnable接口创建子类(ChildrenClass)线程,实例化名称为childrenThread的线程实例,创建Thread类的实例并传入childrenThread线程实例,调用线程的start方法启动线程。具体的实现代码如下:
//step 1:通过实现Runnable接口的方式创建 ChildrenClassThread线程
public class ChildrenClassThread extends SuperClass implements Runnable{
    public void run(){
        System.out.printIn("create a thread by implements Runnable");
    }
}
//step 2:实例化一个 ChildrenClassThread对象
ChildrenClassThread childrenThread= new ChildrenClassThread();
//step 3:创建一个线程对象并将其传入已经实例化好的childrenThread 实例
Thread thread = new Thread(childrenThread);
//step4:调用start方法启动一个线程
thread.start ();
    事实上,在传入一个实现了Runnable的线程实例target给Thread后,Thread的run方法在执行时就会调用target.run方法并执行该线程具体的实现逻辑。在JDK源码中,run方法的实现代码如下:
@override
public void run(){
    if(target!= null){
        target.run();
    }
}

实现Callable接口,重写call()方法

有时,我们需要在主线程中开启多个线程并发执行一个任务,然后收集各个线程执行返回的结果并将最终结果汇总起来,这时就要用到Callable接口。具体的实现方法为:创建一个类并实现Callable接口,在call方法中实现具体的运算逻辑并返回计算结果。具体的调用过程为:创建一个线程池、一个用于接收返回结果的Future List及Callable线程实例,使用线程池提交任务并将线程执行之后的结果保存在Future中,在线程执行结束后遍历Future List中的Future对象,在该对象上调用get方法就可以获取Callable线程任务返回的数据并汇总结果,实现代码如下:

//step 1:通过实现 Callable接口创建 Mycallable线程
public class MyCallable implements Callable<String>(
    private String name;
    public MyCallable(String name){//通过构造函数为线程传递参数,以定义线程的名称
        this.name = name;
    }
    @Override
    public string call() throws Exception{//call方法内为线程实现逻辑
        return name;
    }
}
//step 2:创建一个固定大小为5的线程池
ExecutorService pool= Executors.newFixedThreadPool(5);
//step 3:创建多个有返回值的任务列表list
List<Future> list = new ArrayList<Future>();
for(int i= 0;i<5;i++){
    //step 4:创建一个有返回值的线程实例
    Callable c=new MyCallable(i+"");
    //step 5:提交线程,获取 Future对象并将其保存到Future List中
    Future future = pool.submit(c);
    System.out.println("submit a callable thread:" +i);
    list.add(future);
}
//step 6:关闭线程池,等待线程执行结束
pool.shutdown();
//step 7:遍历所有线程的运行结果
for(Future future:list){
    //从Future对象上获取任务的返回值,并将结果输出到控制台
    System.out.println("get the result from callable thread:"+future.get().toString());
}