并发编程系列(一)创建线程的三种方式及线程如何完成上下文如何切换

目录

1.Thread类:

2.Runable接口

3.Callable接口

4.线程池方式

 5. 线程上下文切换(以Linux为例)


序号名称链接地址
1并发编程系列(一)创建线程的三种方式及线程如何完成上下文如何切换https://blog.csdn.net/qq_38130094/article/details/103443997
2并发编程系列(二)之线程的中断https://blog.csdn.net/qq_38130094/article/details/103444171
3 并发系列(三)线程常用的方法https://blog.csdn.net/qq_38130094/article/details/103446126
4并发编程系列(四)之Thread类源码分析(一)https://blog.csdn.net/qq_38130094/article/details/103448160
5并发编程系列(五)volatile关键字详解https://blog.csdn.net/qq_38130094/article/details/103448564
6并发编程系列(六)volatile 之 as-if-serial 指令重排 volatile内存语义 volatile原理https://blog.csdn.net/qq_38130094/article/details/103543998
7线程系列(七)synchronized使用方式https://blog.csdn.net/qq_38130094/article/details/103537663
8 线程系列(八)synchronized实现原理与应用https://blog.csdn.net/qq_38130094/article/details/103537668
9并发编程系列(九)ThreadLocala是如何解决共享变量的并发问题及源码分析https://blog.csdn.net/qq_38130094/article/details/103665098
10并发编程系列(十)AQS同步器独占锁加锁与解锁-源码解读https://blog.csdn.net/qq_38130094/article/details/103540315
11并发编程系列(十一)AQS同步器共享锁加锁解锁源码解读https://blog.csdn.net/qq_38130094/article/details/103646505
12并发编程系列(十二)AQS同步器条件锁(Condition)加锁解锁源码解读https://blog.csdn.net/qq_38130094/article/details/103679146
13发编程系列(十三)ReentrantLock 重入锁https://blog.csdn.net/qq_38130094/article/details/103843779
14发编程系列(十四)Semaphore信号量https://blog.csdn.net/qq_38130094/article/details/103846420
15发编程系列(十五) CountDownLatch闭锁https://blog.csdn.net/qq_38130094/article/details/103855632
16并发编程系列(十六) CyclicBarrierhttps://blog.csdn.net/qq_38130094/article/details/103859704

1.Thread类:

继承Thread类的创建方式:

  1. 定义Thread类的子类,并重写该类的  run()  方法,该 run() 方法的方法体就代表了线程需要完成的任务。
  2. 创建Thread子类实例,即创建了线程的对象
  3. 调用线程对象的start() 方法来创建并启动线程。
public class HelloThread extends Thread{

    @Override
    public void run() {
        System.out.println("继承Thread类--创建线程");
    }

    public static void main(String[] args) {
        HelloThread ht = new HelloThread();
        ht.start();
    }
}

2.Runable接口

  1. 定义Runable接口的实现类,并且重写该接口的run() 方法,该run() 方法的方法体就是线程的线程执行体
  2. 创建Runable实现类的实例,并且以此实例作为Thread类的target来创建Thread对象,该Thread对象才是真正的线程对象。
public class HelloRunable implements Runnable{
    @Override
    public void run() {
        System.out.printf("实现Runable 接口创建线程");
    }

    public static void main(String[] args) {
        HelloRunable helloRunable = new HelloRunable();
        Thread thread = new Thread(helloRunable);
        thread.start();
    }
}

3.Callable接口

  1. 创建Callable接口的实现类,并且实现 call() 方法,该call() 方法将作为线程的执行体,且该call()方法又返回值,再创建Callable实现类的实例
  2. 使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
  3. 使用FutureTask对象作为Thread对象的target创建并且启动新线程。
  4. 使用FutureTask对象的get()方法来获得子线程执行结束后的返回值。
public class HelloCallable {
    public static void main(String[] args) {

        //使用 FutureTask对象 创建
        //Lambda表达式
        FutureTask futureTask = new FutureTask(() -> {
            int j = 0;
            for (int i = 0; i < 100; i++) {
                j=i+j;
            }
            return j;
        });
        // 创建线程
        Thread thread = new Thread(futureTask);
        // 启动线程
        thread.start();

        //使用这种方式可以拿到线程的返回值
        try {
            //在未获取到结果前会阻塞等待
            futureTask.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

4.线程池方式

详细请见

 5. 线程上下文切换(以Linux为例)

JDK1.2 版本前java是ULT模式;jvm进程自己创建线程;此种方式是伪线程方式;

JDK1.2版本后java是KLT模式;java线程与内核线程 1:1 映射;比如利用Linux的pthread类库实现

线程的上下文切换势必会涉及到用户态到内核态的转变;线程的运行信息执行到哪个指令(线程的状态信息等)都保存在CPU(高速缓存:寄存器L1,L2,L3)中。如果线程还未执行完成CPU会把执行的中间信息存储到TSS(任务状态段)中,当线程再次分配到CPU时间片段的时候会从这回读数据;

上下文切换的开销包括直接开销和间接开销。
直接开销有如下几点:

  • 操作系统保存回复上下文所需的开销
  • 线程调度器调度线程的开销

间接开销有如下几点:

  • 处理器高速缓存重新加载的开销
  • 上下文切换可能导致整个一级高速缓存中的内容被冲刷,即被写入到下一级高速缓存或主存

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值