多线程的创建与Thread的常用方法

简介: 多线程的创建与Thread的常用方法

1.多线程的创建

Thread类

Java是通过java.lang.Thread类来代表线程的。

按照面向对象的思想,Thread类提供了实现多线程的方式。

1.1方式一:继承Thread类

多线程的实现方案一:继承Thread类

① 定义一个子类MyThread继承线程类java.lang.Thread,重写run()方法。

② 创建MyThread类的对象。

③ 调用线程对象的start()方法启动线程(启动后还是执行run方法的)。

方式一优缺点:

优点:编码简单。

缺点:线程类已经继承Thread,无法继承其他类,不利于扩展。

示例代码如下:

publicclassThreadDemo1 {
publicstaticvoidmain(String[] args) {
// 3.实例化线程对象Threadt=newMyThread();
// 4.调用start方法启动子线程(执行run方法)t.start();
for (inti=0; i<5; i++) {
System.out.println("主线程执行输出:"+i);
        }
    }
}
/*** 1.自定义一个线程类继承Thread类*/classMyThreadextendsThread {
/*** 2.重写run方法,其中是此线程要做的工作*/@Overridepublicvoidrun() {
for (inti=0; i<5; i++) {
System.out.println("子线程执行输出:"+i);
        }
    }
}

注:main方法中不是直接调用run方法,而是调用start方法启动线程中的run方法。

直接调用run方法会当成普通方法执行,此时相当于还是单线程执行。

只有调用start方法才是启动一个新的线程执行。

注意将主线程任务放在子线程任务之后,否则主线程执行完毕后再执行子线程,相当于是一个单线程的效果。

1.2方式二:实现Runnable接口

多线程的实现方案二:实现Runnable接口

① 定义一个线程任务类MyRunnable实现Runnable接口,重写run()方法。

② 创建MyRunnable任务对象。

③ 把MyRunnable任务对象交给Thread处理。

④ 调用线程对象的start()方法启动线程。

Thread类构造器

方法名

说明

public Thread(String name)

可以为当前线程指定名称

public Thread(Runnable target)

封装Runnable对象成为线程对象

public Thread(Runnable target ,String name )

封装Runnable对象成为线程对象,并指定线程名称

 

方式二优缺点:

优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强。

缺点:编程多一层对象包装,如果线程有执行结果是不可以直接返回的。

示例代码如下:

publicclassThreadDemo2 {
publicstaticvoidmain(String[] args) {
// 3.创建一个任务对象Runnabletarget=newMyRunnable();
// 4.把任务对象交给Thread处理Threadt=newThread(target);
// 5.启动线程t.start();
for (inti=0; i<5; i++) {
System.out.println("主线程执行:"+i);
        }
    }
}
/*** 定义一个线程任务类,实现Runnable接口*/classMyRunnableimplementsRunnable {
/*** 重写run方法,定义线程的执行任务*/@Overridepublicvoidrun() {
for (inti=0; i<5; i++) {
System.out.println("子线程执行:"+i);
        }
    }
}

多线程的实现方案二:实现Runnable接口(匿名内部类形式)

① 可以创建Runnable的匿名内部类对象。

② 交给Thread处理。

③ 调用线程对象的start()启动线程。

示例代码如下:

publicclassThreadDemo2Other {
publicstaticvoidmain(String[] args) {
newThread(() -> {
for (inti=0; i<5; i++) {
System.out.println("子线程执行:"+i);
            }
        }).start();
for (inti=0; i<5; i++) {
System.out.println("主线程执行:"+i);
        }
    }
}

1.3方式三:JDK 5.0新增:实现Callable接口

前2种线程创建方式都存在一个问题:他们重写的run方法均不能直接返回结果,不适合需要返回线程执行结果的业务场景。

怎么解决这个问题呢?JDK 5.0提供了Callable和FutureTask来实现,这种方式的优点是可以得到线程执行的结果

多线程的实现方案三:利用Callable、FutureTask接口实现

①得到任务对象

1)定义类实现Callable接口,重写call方法,封装要做的事情。

2)用FutureTask把Callable对象封装成线程任务对象。

②把线程任务对象交给Thread处理。

③调用Thread的start方法启动线程,执行任务

④线程执行完毕后、通过FutureTask的get方法去获取任务执行的结果。

FutureTask的常用API

方法名

说明

public FutureTask<>(Callable call)

把Callable对象封装成FutureTask对象

(需要声明任务对象返回值的泛型)

public V get() throws Exception

获取线程执行call方法返回的结果

 

示例代码如下:

publicclassThreadDemo3 {
publicstaticvoidmain(String[] args) {
// 3.创建Callable任务对象Callable<String>call=newMyCallable(10);
// 4.将Callable任务对象交给FutureTask对象,封装为真正的任务对象/*FutureTask对象的作用:实现了Runnable接口,可以交给Thread对象处理可以在线程执行完毕之后通过调用其get方法获取线程执行完毕的返回值*/FutureTask<String>f=newFutureTask(call);
// 5.将任务对象交给Thread处理Threadt=newThread(f);
// 6.启动线程t.start();
Callable<String>call2=newMyCallable(20);
FutureTask<String>f2=newFutureTask(call2);
Threadt2=newThread(f2);
t2.start();
try {
// 若任务没有执行完毕,则代码会在这里等待,直至线程执行完毕,再执行get方法,获取返回值Stringrs=f.get();
System.out.println("第1个结果:"+rs);
        } catch (Exceptione) {
e.printStackTrace();
        }
try {
Stringrs2=f2.get();
System.out.println("第2个结果:"+rs2);
        } catch (Exceptione) {
e.printStackTrace();
        }
    }
}
/*** 1.定义一个任务类,实现Callable接口,需要声明泛型,表明返回值类型*/classMyCallableimplementsCallable<String> {
privateintn;
publicMyCallable(intn) {
this.n=n;
    }
/*** 2.重写call方法(任务方法)   此处为求和方法** @return* @throws Exception*/@OverridepublicStringcall() throwsException {
intsum=0;
for (inti=1; i<=n; i++) {
sum+=i;
        }
return"子线程执行结果"+sum;
    }
}

注:若任务没有执行完毕,则代码会在获取返回值的get方法处等待,直至线程执行完毕,再执行get方法,获取返回值。

2.Thread的常用方法

Thread类常用方法

方法名

说明

String getName ()

获取当前线程的名称,默认线程名称是Thread-索引

void setName (String name)

将此线程的名称更改为指定的名称,

通过构造器也可以设置线程名称

public static Thread currentThread()

返回对当前正在执行的线程对象的引用

public static void sleep(long time)

让当前线程休眠指定的时间后再继续执行,单位为毫秒

public void run()

线程任务方法

public void start()

线程启动方法

 

示例代码如下:

自定义MyThread类

publicclassMyThreadextendsThread {
publicMyThread() {
    }
publicMyThread(Stringname) {
// 为当前线程对象设置名称,交给父类有参构造器初始化super(name);
    }
@Overridepublicvoidrun() {
for (inti=0; i<5; i++) {
System.out.println(Thread.currentThread().getName() +"输出:"+i);
        }
    }
}
测试类publicclassThreadDemo1 {
publicstaticvoidmain(String[] args) throwsInterruptedException {
Threadt=newMyThread("1号线程");
t.start();
Threadt2=newMyThread("2号线程");
t2.start();
// 哪个线程执行它,它就得到哪个线程对象(当前线程对象)Threadm=Thread.currentThread();
System.out.println(m.getName()); // 主线程名称为"main"for (inti=0; i<5; i++) {
if (i==2) {
// 让线程休眠3sThread.sleep(3000);
            }
System.out.println("main线程输出:"+i);
        }
    }
}

程序运行结果如下:

main

main线程输出:0

main线程输出:1

1号线程输出:0

1号线程输出:1

1号线程输出:2

1号线程输出:3

1号线程输出:4

2号线程输出:0

2号线程输出:1

2号线程输出:2

2号线程输出:3

2号线程输出:4

main线程输出:2

main线程输出:3

main线程输出:4

相关文章
|
27天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
19 3
|
27天前
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
17 2
|
27天前
|
Java
在Java多线程编程中,实现Runnable接口通常优于继承Thread类
【10月更文挑战第20天】在Java多线程编程中,实现Runnable接口通常优于继承Thread类。原因包括:1) Java只支持单继承,实现接口不受此限制;2) Runnable接口便于代码复用和线程池管理;3) 分离任务与线程,提高灵活性。因此,实现Runnable接口是更佳选择。
35 2
|
27天前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
29 2
|
27天前
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
17 1
|
27天前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
33 1
|
27天前
|
Java
在Java多线程编程中,`wait()`和`notify()`方法的相遇如同一场奇妙的邂逅
在Java多线程编程中,`wait()`和`notify()`方法的相遇如同一场奇妙的邂逅。它们用于线程间通信,使线程能够协作完成任务。通过这些方法,生产者和消费者线程可以高效地管理共享资源,确保程序的有序运行。正确使用这些方法需要遵循同步规则,避免虚假唤醒等问题。示例代码展示了如何在生产者-消费者模型中使用`wait()`和`notify()`。
25 1
|
27天前
|
安全 Java 开发者
Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用
本文深入解析了Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用。通过示例代码展示了如何正确使用这些方法,并分享了最佳实践,帮助开发者避免常见陷阱,提高多线程程序的稳定性和效率。
34 1
|
27天前
|
Java
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件成立时被唤醒,从而有效解决数据一致性和同步问题。本文通过对比其他通信机制,展示了 `wait()` 和 `notify()` 的优势,并通过生产者-消费者模型的示例代码,详细说明了其使用方法和重要性。
25 1
|
1月前
|
监控 Java
在实际应用中选择线程异常捕获方法的考量
【10月更文挑战第15天】选择最适合的线程异常捕获方法需要综合考虑多种因素。没有一种方法是绝对最优的,需要根据具体情况进行权衡和选择。在实际应用中,还需要不断地实践和总结经验,以提高异常处理的效果和程序的稳定性。
21 3