多线程与高并发1


为什么要学习多线程与高并发?
因为面试。或者初级程序员迈向中高级的一道坎

线程

1.1、线程的基本概念

什么是线程?
线程是相对于进程而言。进程里最小的执行单元

什么是进程?
好比一个程序。qq。在静止状态下。你没去点他。称为程序。当你点击启动qq。这就是启动了一个进程

package com.example.demo;

import java.util.concurrent.TimeUnit;

public class T01_whatisThread {
    private static class T1 extends Thread{
        @Override
        public void run(){
            for (int i=0;i<10;i++){
                try{
                    TimeUnit.MICROSECONDS.sleep(i);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
                System.out.println("T1");
            }
        }
    }

    public static void main(String[] args) {
        new T1().start();
        for (int i=0;i<10;i++) {
            try{
                TimeUnit.MICROSECONDS.sleep(i);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            System.out.println("main");
        }
    }
}

在这里插入图片描述
执行以后会看到t1和main交替输出

1.2、线程创建的几种方式

package com.example.demo;

import java.util.concurrent.*;

public class T02_howtoCreateThread {
    // 1、继承Thread类
    static class MyThread extends Thread{
        @Override
        public void run(){
            System.out.println("hello myThread");
        }
    }

    // 2、实现runnable接口
    static class MyRun implements Runnable{

        @Override
        public void run() {
            System.out.println("hello myRun");
        }
    }

    // 3、实现Callable接口
    static class MyCall implements Callable<String>{

        @Override
        public String call() throws Exception {
            System.out.println("hello Mycall");
            return "success";
        }
    }

    public static void main(String[] args) {
        // 启动线程的5种方式
        // 1
        new MyThread().start();
        // 2
        new Thread(new MyRun()).start();
        // 3
        new Thread(() -> {
            System.out.println("hello lambda");
        }).start();
        // 4
        Thread t = new Thread(new FutureTask<String>(new MyCall()));
        t.start();
        // 5
        ExecutorService service = Executors.newCachedThreadPool();
        service.execute(() ->{
            System.out.println("hello threadPoll");
        });
        service.shutdown();
    }
}

在这里插入图片描述

####面试题:启动线程的三种方法?
1、new Thread继承类.start()
2、new Thread(new Runnable实现类).start()
3、线程池创建
3.1、先用Executors的方法创建ExecutorService对象
3.1.1、Executors创建4种线程池为哪四种?
1、newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
2、newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
3、newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
4、newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

3.2、调用execute()方法执行线程池
3.3、执行完毕后调用shutdown方法关闭线程池

####面试题:创建线程有几种方法?
1、继承Thread类
2、实现Runnable接口
3、实现Callable接口

####面试题:为什么线程执行调用的是start方法而不是run方法?
直接调用线程的run方法。没有实现多线程。而是当前线程立即执行完run方法后再执行下一句代码。而start方法真正使线程进入就绪状态。等待cpu分配时间片。而不是立即执行。

package com.example.demo;

public class T03_sleep_yield_join {
    static class MyThread extends Thread{
        @Override
        public void run(){
            System.out.println(Thread.currentThread().getName()+"============");
        }
    }

    public static void main(String[] args) {
        MyThread m = new MyThread();
        // 定义两个线程名
        Thread thread1 = new Thread(m,"thread1");
        Thread thread2 = new Thread(m,"thread2");

        //测试直接用run方法和start方法区别
        thread1.run();
        thread2.start();
    }
}

在这里插入图片描述
所以直接调run方法会出错

1.3、线程的几种方法

package com.example.demo;

public class T03_sleep_yield_join {
    public static void main(String[] args) {
        //testSleep();
        //testYield();
        testJoin();
    }

    /**
     * sleep,睡眠。当前线程暂停一段时间让给别的线程去运行。当前线程由睡眠时间决定。等
     * 睡眠时间到规定时间自动复活
     */
    static void testSleep(){
        new Thread(() -> {
            for (int i = 0; i<100 ;i++){
                System.out.println("A"+i);
                try{
                    Thread.sleep(500);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        }).start();
    }

    /**
     * yield 当前线程正在执行时候停下来进入等待队列。回到等待队列的他依旧可能会被拿出来
     * 继续执行。当然更大程度和可能是原来等待的线程。也就是我让出cpu,抢不抢得到是你们的事
     */
    static void testYield(){
        new Thread(() -> {
            for (int i = 0; i<100 ;i++){
                System.out.println("A"+i);
                if (i%10 == 0) Thread.yield();
            }
        }).start();

        new Thread(() -> {
            for (int i = 0; i<100 ;i++){
                System.out.println("B"+i);
                if (i%10 == 0) Thread.yield();
            }
        }).start();

    }

    /**
     * join 自己当前线程和调用join的线程执行时。当前线程等待。等调用线程执行完毕。当前线程再执行。
     * t1 t2两个线程。在t1执行过程中调用t2.join()则跑到t2执行完毕后再执行t1.一般不自己join自己
     * 无意义
     */
    static void testJoin(){
        Thread t1 = new Thread(() ->{
            for (int i = 0; i< 100; i++){
                System.out.println("A"+i);
                try {
                    Thread.sleep(0);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        });

        Thread t2 = new Thread(() -> {
            try {
                t1.join();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            for (int i = 0 ; i< 100; i++){
                System.out.println("B"+i);
                try {
                    Thread.sleep(0);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        t1.start();
        t2.start();
    }
}

sleep
在这里插入图片描述

yield
在这里插入图片描述

join
在这里插入图片描述

sleep当前线程睡眠。让给别的线程执行。睡眠时间到当前线程复活
yield线程礼让。让出cpu。进入等待区。但同时也可能被继续执行。其他线程能不能抢到资源都不一定
join 在t1线程里调用t2.join方法。直接执行t2线程。直到t2执行完毕后再回来执行t1

1.4、线程的六种状态

1、 初始(NEW):新创建了一个线程对象,但还没有调用start()方法。

2、 运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。

线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。

3、 阻塞(BLOCKED):表示线程阻塞于锁。

4、 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。

5、 超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。

6、 终止(TERMINATED):表示该线程已经执行完毕

####线程的几种状态都由jvm管理?还是由操作系统管理?
全部都由jvm管理,jvm是操作系统一个普通程序。两者不分家

####线程什么状态会被挂起。挂起是否也是一种状态?
运行中的时候,cpu执行多个线程。一会执行这个线程一下。一会执行那个一下。当线程被cpu挂起的时候。被动的。所以挂起不是线程自己的状态。

package com.example.demo;

public class T04_ThreadState {
    static class MyThread extends Thread{
        @Override
        public void run(){
            System.out.println(this.getState());

            for(int i = 0; i<10; i++){
                try{
                    Thread.sleep(500);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }

                System.out.println(i);
            }
        }

        public static void main(String[] args) {
            Thread t = new MyThread();
            System.out.println(t.getState()); // new状态
            t.start(); // Runnable状态
            try{
                t.join();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            // join之后是Timenated状态
            System.out.println(t.getState());
        }
    }
}

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值