java多线程框架推荐-Java线程的使用方法和属性分析:线程
前言
在java中一个线程是使用Thread的实例来表示,所有线程对象都必须是Thread的子类实例或是Thread的实例,它位于java.lang包中,是Java中非常常用也是非常重要的一个基础类。Thread类实现了Runnable接口,它有不少非常重要的方法和属性:
那么创建Java的线程一般有哪几种方式呢?一、继承Thread类创建线程类
1. 定义Thread类的子类ThreadDemo,并重写该Thread类的run()方法java多线程框架推荐,在run()方法中执行该线程的主要逻辑。
2. 在主线程上创建Thread子类的实例,即创建了一个线程对象。
3. 调用线程对象的start()方法来启动该线程。
// 继承Thread类,创建一个新的线程类
public class ThreadDemo extends Thread{
// 重写了Thread类的run()方法,将需要并发执行的用户业务代码编写在继承的run()方法中
@Overrite
public void run(){
System.out.println(getName()+" 这里执行线程的业务逻辑");
}
}
public class AppDemo {
public static void main(String[] args) {
ThreadDemo threadDemo = new ThreadDemo();
// 启动线程
threadDemo.start();
System.out.println("线程名:"+Thread.currentThread().getName()+" 运行结束");
}
}
执行结果:
线程名:main 运行结束
Thread-0 这里执行线程的业务逻辑
二、实现Runnable接口,创建线程目标类
有了Thread类了,为什么还需要多一个Runnable的接口方式来创建一个线程呢?那是因为Java继承的一个特征,extend只能一个父类,当一个子类已经继承了一个父类时,此时你希望这个类成为一个线程类,是不行的,但它能实现Runnable接口。
1.定义Runnable接口的实现类,并实现run()方法,在run()方法中执行该线程的主要逻辑。
⒉.创建Runnable实现类的实例,并将其作为Thread的target来创建Thread对象,Thread对象为线程对象。
3.调用线程对象的start()方法来启动该线程。
public class RunnableThreadDemo implements Runnable {
// 重写了Runnable类的run()方法,将需要并发执行的用户业务代码编写在继承的run()方法中
@0verrite
public void run( ){
System.out.println(Thread.currentThread().getName()+" 这里执行线程的业务逻辑" )
}
}
public class AppDemo {
public static void main(String[] args) {
RunnableThreadDemo threadDemo = new RunnableThreadDemo();
// 启动线程
threadDemo.start();
System.out.println("线程名:"+Thread.currentThread().getName()+" 运行结束");
}
}
执行结果:
线程名:main 运行结束
Thread-0 这里执行线程的业务逻辑
三、使用匿名内部类,实现创建Thread子类
跟方式一类似,只是不需要创建一个单独的类文件来继承Thread,而是使用了匿名类来完成,代码如下:
public class AppDemo {
public static void main(String[] args) {
Thread thread = new Thread() {
@Override
public void run() {
System.out.println(getName()+" 这里执行线程的业务逻辑");
}
};
thread.start();
System.out.println("线程名:"+Thread.currentThread().getName()+" 运行结束");
}
}
执行结果:
线程名:main 运行结束
Thread-0 这里执行线程的业务逻辑
四、使用匿名内部类,实现Runnable接口
跟方式二类似,区别在于使用匿名类来完成,代码如下:
public class AppDemo {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" 这里执行线程的业务逻辑" );
}
});
thread.start();
System.out.println("线程名:"+Thread.currentThread().getName()+" 运行结束");
}
}
执行结果:
Thread-0 这里执行线程的业务逻辑
线程名:main 运行结束
什么?这跟方式二执行的结果不一样?这里是没问题的,这里是两个线程在跑着,哪个线程先跑是跟cpu的调度有关,跟代码的先后无关。这点请紧记。
五、使用lambda表达式来完成
使用lambda表达式使得代码更简洁,实现其实跟方式三一样,只是使用lambda来代替匿名类。
public class AppDemo {
public static void main(String[] args) {
Thread thread = new Thread(()->{
System.out.println(Thread.currentThread().getName()+" 这里执行线程的业务逻辑");
});
thread.start();
System.out.println("线程名:"+Thread.currentThread().getName()+" 运行结束");
}
}
执行结果:
线程名:main 运行结束
Thread-0 这里执行线程的业务逻辑
六、实现Callable接口
继承Thread类或者实现Runnable接口这两种方式来创建线程类有一个缺陷,就是不能获取异步执行的结果,即在主线程启动子线程后,能run起来就分道扬镳了,但在很多场景上需要获取到异步执行的结果,这个时候就需要实现Callable接口了。这是在1.5之后提供的一种创建多线程的方法,通过Callable接口和FutureTask类互相作用来完成线程执行以及在主线程中获取执行的结果。
Callable接口位于java.util.concurrent包中:
@FunctionalInterface
public interface Callable {
V call() throws Exception;
}
创建步骤如下:
首先定义一个 Callable 的实现类,并实现call方法。call方法是带返回值的。然后通过FutureTask的构造方法,把这个Callable 实现类传进去。把 FutureTask作为 Thread 类的 target ,创建Thread线程对象。通过FutureTask 的get方法获取线程的执行结果。
public class CallableTaskDemo implements Callable {
// 编写好异步执行的具体逻辑,可以有返回值。
// (Runnable接口中的run()方法是没有返回值得,Callable接口的call()方法有返回值)
@Override
public Long call() throws Exception {
Long startTime = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName()+" 线程开始运行");
Thread.sleep(1000);
for(int i=0;i<100000000;i++){
int j = i*10000;
}
Long endTime = System.currentTimeMillis();
Long used = endTime-startTime;
System.out.println(Thread.currentThread().getName()+" 线程结束运行");
return used;
}
}
public class AppDemo {
public static void main(String[] args) throws InterruptedException {
CallableTaskDemo callableTaskDemo = new CallableTaskDemo();
FutureTask futureTask = new FutureTask(callableTaskDemo);
Thread thread = new Thread(futureTask,"callableTaskThread");
thread.start();
Thread.sleep(500);
System.out.println("main线程执行一会");
for(int i=0;i<100000000/2;i++){
int j = i*10000;
}
// 获取并发任务的执行结果
try {
System.out.println(thread.getName()+" 线程占用时间:"+futureTask.get());
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
执行结果:
callableTaskThread 线程开始运行
main线程执行一会
callableTaskThread 线程结束运行
callableTaskThread 线程占用时间:1008
七、使用自带线程池
使用线程池的一个很重要的原因是线程的复用性。我们知道线程资源在服务器上来看java多线程框架推荐,是一种非常昂贵的资源,如果使用不当,服务器的负载是非常高,并且可能会出现超负荷的情况,往往会导致服务器死机等问题,所以线程的合理分配就变得是一个非常有意思的话题。线程池往往就能很好地解决这个问题,设定一个线程池,往线程池中注入固定的线程数,超过的线程的任务数,要不等待,要不抛弃。大大地复用了线程,减少线程频繁创建与销毁,提高了服务器的可用率。
Java在线程池上也有多种类型的支持,在不同的场景下可选择不同类型的线程池。
一般的使用方式如下:
首先,定义一个 Runnable 的实现类,重写run方法然后创建一个拥有固定线程数的线程池最后通过ExecutorService对象的execute 方法传入线程对象
public class RunnableTaskDemo implements Runnable {
@Override
public void run() {
for(int i=0;i<3;i++){
System.out.println(Thread.currentThread().getName()+" 轮次:"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class CallableTaskDemo implements Callable {
@Override
public Long call() throws Exception {
Long startTime = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName()+" 线程开始运行");
for(int i=0;i<3;i++){
System.out.println(Thread.currentThread().getName()+" 轮次:"+i);
Thread.sleep(1000);
}
Long used = System.currentTimeMillis()-startTime;
System.out.println(Thread.currentThread().getName()+" 线程结束运行");
return used;
}
}
public class AppDemo {
private static ExecutorService threadpool = Executors.newFixedThreadPool(3);
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 1、执行Runnbale类型的target目标实例,无返回
threadpool.execute(new RunnableTaskDemo());
//2、 执行Runnbale类型的target目标实例,无返回,内部类形式
threadpool.execute(new Runnable() {
@Override
public void run() {
for(int i=0;i<3;i++){
System.out.println(Thread.currentThread().getName()+" 轮次:"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
// 3、提交Callable执行目标实例,有返回
Future future = threadpool.submit(new CallableTaskDemo());
System.out.println("异步执行的结果为:" + future.get());
}
}
执行结果:
pool-1-thread-1 轮次:0
pool-1-thread-2 轮次:0
pool-1-thread-3 线程开始运行
pool-1-thread-3 轮次:0
pool-1-thread-2 轮次:1
pool-1-thread-1 轮次:1
pool-1-thread-3 轮次:1
pool-1-thread-2 轮次:2
pool-1-thread-1 轮次:2
pool-1-thread-3 轮次:2
pool-1-thread-3 线程结束运行
异步执行的结果为:3002