说说多线程及创建多线程的四种方式

一、线程是什么?
在计算机中当一个程序运行的时候就会创建至少一个进程,例如当我们运行WPS office 的时候,系统就会创建进程来处理我们平时的一些操作,当我们打开任务管理器的时候,在进程的列表里面就可以找到WPS Office.exe的运行程序;
在计算机中处理进程之外还有另一个概念就是线程,线程是存在于进程当中,一个进程可以包含多个线程;当我们的计算机有多核处理器的时候,使用多线程可以加快程序的运算速率;如果一个进程中只有一个线程,当程序遇到一个I/O或网络等其它需要等待的时候,由于程序是单线程的,那么程序只能等待这个运算结束的时候再继续运行,而此时CPU是空闲的,这样会大大的降低程序的效率;当用多个线程的时候,在某个线程遇到比较上述情况的时候,该线程可以继续自己的等待,但是其他的线程也可以使用CPU进行计算,使得CPU一直处于运算状态,这样就会很大的提高程序执行效率;另一方面,多线程可以使用多个处理器核心,来提高运行速度。

二 多线程的四种实现方式

1 继承Thread类,
1)说明:
通过创建Thread类的子类来创建线程。

2)步骤:

(1)创建一个Thread类的子类

(2)重写继承类的run()方法,编写线程执行体

(3)创建线程对象,调用start()方法启动线程 
3) 代码

/**
 * @Description: 多线程实现方式之一:继承thread
 * @Author: Gyl
 * @Time: 2023/01/18
 */
public class CytInheritThread extends Thread{
    
    

    @Override
    public void run() {
    
    
        //执行线程业务的方法
        for (int i = 0; i < 50; i++) {
    
    
            //返回正在执行的线程实例
            Thread thread = Thread.currentThread();
            //getName()获取当前线程实例的名称
            System.out.println(thread.getName()+"我在听音乐-子线程"+i);
        }
    }


}
/**
 * @Description: 多线程实现方式之一:继承thread
 * @Author: Gyl
 * @Time: 2023/01/18
 */
public class CytRealizeInheritThread {
    
    
    public static void main(String[] args) {
    
    

        CytInheritThread inheritExtendsThread=new CytInheritThread();
        inheritExtendsThread.start();

        for (int i = 0; i < 50; i++) {
    
    
            System.out.println("我在看书-主线程"+i);
        }

    }
}

2 实现Runnable接口

1)说明
java是单继承的,在某些情况下一个类可能已经继承了某个父类,这时在用继承Thread类方法来创建线程显然不可能了。
java设计者们提供了另外一个方式创建线程,就是通过实现Runnable接口来创建线程

2)步骤:
(1)创建一个实现Runnable接口的类
(2)在实现类中重写Runnable接口的run方法,设置线程任务。
(3)创建实现类的对象
(4)将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象,通过Thread类的对象调用start()方法

3)代码

/**
 * @Description: 多线程实现方式之二:实现Runnable 调用
 * @Author: Gyl
 * @Time: 2023/01/18
 */
public class CytRunnable implements Runnable {
    
    
    @Override
    public void run() {
    
    
        //执行线程业务的方法
        for (int i = 0; i < 50; i++) {
    
    
            //返回正在执行的线程实例
            Thread thread = Thread.currentThread();
            //getName()获取当前线程实例的名称
            System.out.println(thread.getName()+"我在听音乐-子线程"+i);
        }
    }
}
/**
 * @Description: 多线程实现方式之二:实现Runnable 调用
 * @Author: Gyl
 * @Time: 2023/01/18
 */
public class CytRealizeRunnable {
    
    
    public static void main(String[] args) {
    
    
        CytRunnable cytRunnable=new CytRunnable();
        cytRunnable.run();
        for (int i = 0; i < 50; i++) {
    
    
            System.out.println("我在看书-主线程"+i);
        }
    }
}

4 ) 实现Runnable接口好处
(1).避免了单继承的局限性

java一个类只能继承一个类,类继承了其它的类就不能继承Thread类

如果采用Runnable接口的方式,继承类,也可实现多线程。

(2).增强了程序的扩展性,降低了程序的耦合性(解藕)
a 实现Runnable接口的方式,把设置线程任务和开启新线程进行了分离(解藕)
b 实现类中,重写了run方法,用来设置线程任务
c 创建Thread类对象,调用start方法,用来开启新线程

3 使用callable方式创建线程
1)说明:
使用Callable接口创建线程能够返回数据。与Runnable接口创建线程的方式有点类似,也是需要通过Thread类来创建线程。由于Thread类的构造函数中没有Callable接口,选用了FutureTask类来作为连接创建线程。
 FutureTask类实现了RunnableFuture接口,而RunnableFuture接口继承了Runnable, Future接口。在FutureTask类中构造函数可以传入Callable对象,以此建立关系。
 通过FutureTask中的get()方法来获取Callable接口中的call()方法的返回值。

2)步骤:
1:第一步:继承callable接口并实现call方法,并返回一个sum(随意)值
2:执行Callable方式,需要FutureTask实现类的支持,用于接收运算结果。 FutureTask 是 Future 接口的实现类

3)代码:

import java.util.Random;
import java.util.concurrent.Callable;

/**
 * @Description: 多线程实现方式之三:实现Callable
 * @Author: Gyl
 * @Time: 2023/01/18
 */
public class CytCallable implements Callable {
    
    

    @Override
    public Object call() throws Exception {
    
    
        //执行线程业务的方法
        for (int i = 0; i < 50; i++) {
    
    
            //返回正在执行的线程实例
            Thread thread = Thread.currentThread();
            //getName()获取当前线程实例的名称
            System.out.println(thread.getName()+"我在听音乐-子线程"+i);
        }
        //获取随机数
        Random random = new Random();
        int k=random.nextInt(10);
        return k;
    }
}
import java.util.concurrent.FutureTask;

/**
 * @Description: 多线程实现方式之三:实现Callable
 * @Author: Gyl
 * @Time: 2023/01/18
 */
public class CytRealizeCallable {
    
    

    public static void main(String[] args) {
    
    
        CytCallable cytCallable = new CytCallable();
        //需要一个callable的实现
        //1、执行callable 方式,需要futuretask实现类的支持,用于接受运算结果
        FutureTask<Integer> fu = new FutureTask<>(cytCallable);
        new Thread(fu).start();
        try {
    
    
            int k = fu.get();
            System.out.println(k);
        }catch (Exception e){
    
    
            e.printStackTrace();
        }

    }
}

4) 实现runnable和callable的区别
(1) 都是执行多线程,但是方法名称不同 run() 和call()
(2) 实现Runnable方法是没有返回值,无法获取线程业务方法执行结果 而Callable相反
(3) 实现Runnable方法没有抛出异常 而Callable有异常处理,并且获取异常

4 线程池
1)说明:
java线程的创建非常昂贵,需要JVM和OS(操作系统)互相配合完成大量的工作。而java高并发频繁的创建和销毁线程的操作是非常低效的,如何降低java线程的创建成本,就必须要使用到线程池。

合理地使用线程池能够带来3个好处:

第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。

第三:提高线程的可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,
还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控。

2)创建方式:
创建方式有7种:
(1). Executors.newFixedThreadPool:创建一个固定大小的线程池,可控制并发的线程数,超出的线程会在队列中等待;
(2). Executors.newCachedThreadPool:创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后会回收,若线程数不够,则新建线程;
(3). Executors.newSingleThreadExecutor:创建单个线程的线程池,它可以保证先进先出的执⾏顺序;
4. Executors.newScheduledThreadPool:创建一个可以执行延迟任务的线程池;
5. Executors.newSingleThreadScheduledExecutor:创建一个单线程的可以执行延迟任务的线程池。
6. Executors.newWorkStealingPool:创建一个抢占式执行的线程池(任务执⾏顺序不确定)。
7. ThreadPoolExecutor:最原始的创建线程池的⽅式,它包含了 7 个参数可供设置。

3)代码

/**
 * @Description: 多线程实现方式之四:使用线程池
 * @Author: Gyl
 * @Time: 2023/01/18
 */
public class CytPool implements Runnable {
    
    

    @Override
    public void run() {
    
    
        //执行线程业务的方法
        for (int i = 0; i < 50; i++) {
    
    
            //返回正在执行的线程实例
            Thread thread = Thread.currentThread();
            //getName()获取当前线程实例的名称
            System.out.println(thread.getName()+"我在听音乐-子线程"+i);
        }
    }
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
 * @Description: 多线程实现方式之四:使用线程池
 * @Author: Gyl
 * @Time: 2023/01/18
 */
public class CytRealizePool {
    
    

    public static void main(String[] args) {
    
    
        //实例化线程类
        CytPool cytPool =new CytPool();
        //使用Executors创建固定长度为4的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(4);
        //调用execute启动线程
        executorService.execute(cytPool);
    }
}

猜你喜欢

转载自blog.csdn.net/helloworldchina/article/details/128752716