2021-10-11线程复习

第一种继承Thread类

package cn.tedu.day01;
/*继承Thread类*/
public class ThreadDemo1 extends Thread{
    @Override
    public void run() {
        for (int i=1;i<=200;i++){
            System.out.println(getName()+i);
        }
    }
}
package cn.tedu.day01;

public class ThreadTest1 {
    public static void main(String[] args) {
        ThreadDemo1 threadDemo1 = new ThreadDemo1();
        threadDemo1.start();
        for (int i = 0; i < 200; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }
    }
}

第二种实现Runnable接口

package cn.tedu.day01;
/*实现runnable接口*/
public class ThreadDemo2 implements Runnable{
    @Override
    public void run() {
        for (int i=1;i<=100;i++){
            System.out.println(Thread.currentThread().getName()+i);
        }
    }
}

package cn.tedu.day01;

public class ThreadTest2 {
    public static void main(String[] args) {
        ThreadDemo2 threadDemo2 = new ThreadDemo2();
        Thread thread = new Thread(threadDemo2,"新线程");
        thread.start();
        for (int i = 0; i < 200; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }
    }
}

第三种:实现Callable接口

  1. 创建一个类,实现Callable接口
  2. 重写Callable接口中的call方法
  3. 创建Callable接口的实现类对象
  4. 创建FutureTask创建,把Callable实现类对象传入到FutureTask构造方法中
  5. 创建Thread对象,把FutureTask对象传入到Thread类的构造方法中
  6. 开启线程
  7. 通过FutureTask对象调用get方法,拿到返回值,线程才结束。
package cn.tedu.day01;

import java.util.Random;
import java.util.concurrent.Callable;
/*创建一个类,实现Callable接口(泛型类型自定义)
重写Callable接口中的call方法
创建Callable接口的实现类对象
创建FutureTask创建,把Callable实现类对象传入到FutureTask构造方法中
创建Thread对象,把FutureTask对象传入到Thread类的构造方法中
开启线程
通过FutureTask对象调用get方法,拿到返回值,线程才结束。
* */
public class ThreadDemo3 implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        return new Random().nextInt(10);
    }
}

package cn.tedu.day01;

import java.util.concurrent.FutureTask;

public class ThreadTest3 {
    public static void main(String[] args) throws Exception{
        ThreadDemo3 threadDemo3 = new ThreadDemo3();
        FutureTask<Integer> futureTask = new FutureTask<>(threadDemo3);
        Thread thread = new Thread(futureTask);
        thread.start();
        //拿到线程返回值时,线程才结束
        Integer integer = futureTask.get();
        System.out.println(integer);
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }
    }
}

优缺点比较

  • 第一种继承Thread类
  • 代码编写简单,可以直接使用Thread类中的方法
  • java中类属于单继承,已经继承Thread类,无法继承其它类
  • 第二种实现Runnable接口
  • 避免了单继承的局限性,可以理解为降低耦合性
  • 代码比较复杂,如果想要使用Thread中的方法,需要先获取当前线程的对象,再调用方法
  • 第三种实现Callable接口
  • 有返回值,可以抛出异常,避免单继承的局限性
  • 实现起来比较复杂,访问线程中的方法,需要使用thread.currentThread()

线程状态!线程的生命周期!

  • 创建线程,进入到了新建状态,调用start()方法,得到cpu调度,进入运行状态,正常执行完进行死亡(销亡)状态;没有得到cpu调度,进行阻塞状态
  • 运行状态调用sleep(long)进入休眠状态,执行时间到,再进行cpu执行权判断。
  • 运行状态调用Object.wait()进行无限永久等待状态,Object.notify()唤醒,再进行cpu执行权判断。
  1. sleep方法在同步代码块或者同步方法中不释放锁的
  2. package cn.tedu.day01;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class ThreadTest4 {
        public static void main(String[] args) throws InterruptedException {
            for (int i = 0; i < 20; i++) {
                Date date = new Date();
                SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
                String format = sdf.format(date);
                System.out.println(format);
                Thread.sleep(1000);
            }
        }
    }
    

  3. wait方法在同步代码块或者同步方法中释放锁
  4. join方法用线程对象调用,半路杀出个程咬金(代码案例)
  5. package cn.tedu.day01;
    /*
    * 匿名内部类 创建类的子类对象或者接口的实现类对象!!
    * */
    public class ThreadDemo4 {
        public static void main(String[] args) {
            final Thread t1=new Thread("线程一"){
                @Override
                public void run() {
                    for (int i=1;i<=10;i++){
                        System.out.println(Thread.currentThread().getName()+i);
                    }
                }
            };
            t1.start();
            new Thread("线程二"){
                @Override
                public void run() {
                    for (int i=1;i<=10;i++){
                        System.out.println(Thread.currentThread().getName()+i);
                        if (i==5){
                            try {
                                t1.join();
                            } catch (InterruptedException e) {
                            }
                        }
                    }
                }
            }.start();
        }
    }
    

    yied :让出cpu执行权 ,具备抢夺cpu执行权能力!

线程的同步(同步锁)

  • 在多线程并发中,有多段代码同时执行,我们需要在某一段代码在执行过程中,cpu不要切换到其它线程上,就需要用到同步
  • 匿名内部类,使用本方法的局部变量,必须final修饰
  • 同步代码块;synchronized(任意的唯一锁对象)
  • 同步方法:只需要在方法上加上synchronized即可(非静态方法锁得是this,静态方法锁得是当前类的字节码对象)
  • 线程同步:优点:多线程共享数据,,,可以保证数据的安全! 缺点:效率低,可能会出现死锁
package cn.tedu.day01;

public class ThreadTest5 {
    public static void main(String[] args) {
        final ThreadDemo6 threadDemo6 = new ThreadDemo6();
        new Thread("A"){
            @Override
            public void run() {
                while (true){
                    threadDemo6.print1();
                }
            }
        }.start();
        new Thread("B"){
            @Override
            public void run() {
                while (true){
                    threadDemo6.print2();
                }
            }
        }.start();
    }
}
class ThreadDemo6{
    public synchronized void print1(){
        System.out.print("李");
        System.out.print("文");
        System.out.print("斌");
        System.out.println("斌");

    }
    public synchronized void print2(){
        System.out.print("徐");
        System.out.print("晴");
        System.out.print("晴");
        System.out.println("晴");
    }
}

线程的通信(可以交叉进行)

多个线程并发执行时,默认情况下cpu是随机进行切换线程,如果希望多个进程之间可以规律执行,这时候就必须加以控制,用到线程的通信!!!

线程等待:wait()

唤醒等待的线程:notify()

注意:这两个方法必须使用在同步当中,并且使用同步锁进行调用

package cn.tedu.day01;

public class ThreadTest5 {
    public static void main(String[] args) {
        final ThreadDemo6 threadDemo6 = new ThreadDemo6();
        new Thread("A"){
            @Override
            public void run() {
                while (true){
                    try {
                        threadDemo6.print1();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
        new Thread("B"){
            @Override
            public void run() {
                while (true){
                    try {
                        threadDemo6.print2();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }
}
class ThreadDemo6{
    int flag=1;
    public synchronized void print1() throws InterruptedException {
        if (flag!=1){
            this.wait();
        }
        System.out.print("李");
        System.out.print("文");
        System.out.print("斌");
        System.out.println("斌");
        flag=2;
        this.notify();
    }
    public synchronized void print2() throws InterruptedException {
        if (flag!=2){
            this.wait();
        }
        System.out.print("徐");
        System.out.print("晴");
        System.out.print("晴");
        System.out.println("晴");
        flag=1;
        this.notify();
    }
}

线程当中如何抛出异常

callable可以抛出异常,其它可以捕获,或者抛出自定义异常

多线程如何避免死锁(同步代码 进行嵌套 )

线程池的工作原理

为什么使用线程池?

如果并发的线程数量很多,并且每一个线程执行一个很短的任务就结束了,这样频繁的创建线程会大大降低系统的效率;因为频繁创建和销毁线程需要时间,线程池相当于一个容器,里面可以容纳很多的线程,池子中的线程可以反复的进行使用,省去了频繁创建和销毁的过程,从而提高效率

优点:

  1. 降低资源消耗
  2. 提高响应速度(当使用线程时,不需要等待创建,直接从线程池进行获取使用)
  3. 提高线程的可管理性

Jdk5之前,需要我们自己手动创建线程池

集合进行管理,add(new Thread(...)),remove传索引,返回的是删除元素的对象,可以使用,list.add进行归还,LinkedList.removeFirst()返回对象,即为线程对象,addFirst归还线程

jdk5之后,jdk内置了线程池

Executor并不是一个线程池,而只是一个执行线程的工具,而真正的线程池是ExecutorService其实现类ThreadPoolExector

线程池用到的是阻塞队列

入队:非阻塞队列,当入队元素超过容器长度,数据丢失;阻塞队列,当入队元素超过容器长度,进行等待,出队完成后在进行存储。

出队:非阻塞队列,容器没有元素,直接得到null值,阻塞队列,容器中没元素,等待有入队之后,再进行出队。

 

  •  一个任务,已存在的一个核心线程,可以解决

  • 多个任务,等待的任务!!没有超过阻塞队列长度,存放在阻塞队列中,等待核心线程依次执行!

  • 多个任务,等待的任务超过了阻塞队列的最大长度,就会开始创建新的线程,如果新建线程数+核心线程数>最大线程数,直接报错;如果没有超过,那就正常创建,核心线程增加,分摊任务!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值