0
点赞
收藏
分享

微信扫一扫

Java:多线程

fbd4ffd0717b 2022-04-05 阅读 75
java

Java:多线程

多线程的创建

方式一:继承Thread类

public class test {
    public static void main(String[] args) {
        Thread t = new MyTread();
        t.start();

        for (int i=0;i<1000;i++){
            System.out.println("主线程执行输出:"+i);
        }

    }
}
class MyTread extends Thread{
    @Override
    public void run() {
        for (int i=0;i<1000;i++){
            System.out.println("子线程执行输出:"+i);
        }
    }
}
  • 为什么不直接调用了run方法,而是调用start启动线程?
    直接调用run方法会当成普通方法执行,此时相当于还是单线程执行。
    只有调用start方法才是启动一个新的线程执行。

方式二:实现Runnable接口

1、定义一个线程任务类MyRunnable实现Runnable接口,重写run()方法
2、创建MyRunnable任务对象
3、把MyRunnable任务对象交给Thread处理。
4、调用线程对象的start()方法启动线程

public class test {
    public static void main(String[] args) {
        Runnable target = new MyRunnable();
        Thread t = new Thread(target);
        t.start();

        for (int i=0;i<1000;i++){
            System.out.println("主线程执行输出:"+i);
        }

    }
}
class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i=0;i<1000;i++){
            System.out.println("子线程执行输出:"+i);
        }
    }
}

匿名内部类写法:

        Runnable target = new Runnable() {
            @Override
            public void run() {
                for (int i=0;i<1000;i++){
                    System.out.println("子线程执行输出:"+i);
                }
            }
        };
        Thread t = new Thread(target);
        t.start();

@FunctionalInterface
Runnable还能实现函数化接口

        new Thread(()->{
            for (int i=0;i<1000;i++){
                System.out.println("子线程执行输出:"+i);
            }
        }).start();

优缺点:
优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强。
缺点:编程多一层对象包装,如果线程有执行结果是不可以直接返回的。

方式三:JDK 5.0新增:实现Callable接口

在这里插入图片描述

import jdk.nashorn.internal.codegen.CompilerConstants;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

//        实现Callable,结合FutureTask
public class test {
    public static void main(String[] args){
        //3、创建Callable任务对象
        Callable<String> call = new MyCallable(100);
        //4、把Callable对象任务交给 FutureTask 对象(Runnable接口的对象,可以交给Thread,可以在线程执行完毕之后,使用Get方法得到结果)
        FutureTask<String> f1 = new FutureTask<>(call);
        //5、交给Thread处理
        Thread t1 = new Thread(f1);
        t1.start();

        Callable<String> call2 = new MyCallable(100);
        FutureTask<String> f2 = new FutureTask<>(call2);
        //5、交给Thread处理
        Thread t2 = new Thread(f2);
        t2.start();

        try {
            // 如果f1任务没有执行完毕,这里的代码会等待,直到线程1跑完才提取结果。
            String rs1 = f1.get();
            System.out.println("第一个结果:" + rs1);
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            // 如果f2任务没有执行完毕,这里的代码会等待,直到线程2跑完才提取结果。
            String rs2 = f2.get();
            System.out.println("第二个结果:" + rs2);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

// 1、定义一个任务类 实现Callable接口(泛型接口)
class MyCallable implements Callable<String>{
    private int n;
    //2、重写任务方法
    public MyCallable(int n){
        this.n = n;
    }
    @Override
    public String call() throws Exception {
        int sum = 0;
        for(int i=0;i<=n;i++){
            sum += i;
        }
        return "子线程执行的结果是:" + sum;
    }
}

优缺点:
优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强。
可以在线程执行完毕后去获取线程执行的结果。
缺点:编码复杂一点。

在这里插入图片描述

Thread常用API

Thread常用api和构造器
在这里插入图片描述在这里插入图片描述

线程同步

在这里插入图片描述

方式一:同步代码块

作用:把出现线程安全问题的核心代码给上锁。
原理:每次只能一个线程进入,执行完毕后自动解锁,其他线程才可以进来执行。
在这里插入图片描述
锁对象要求
理论上:锁对象只要对于当前同时执行的线程来说是同一个对象即可。

在这里插入图片描述
锁对象的规范要求

  • 规范上:建议使用共享资源作为锁对象。
  • 对于实例方法建议使用this作为锁对象。
  • 对于静态方法建议使用字节码(类名.class)对象作为锁对象。

方式二:同步方法

同步方法
作用:把出现线程安全问题的核心方法给上锁。
原理:每次只能一个线程进入,执行完毕以后自动解锁,其他线程才可以进来执行。
在这里插入图片描述在这里插入图片描述同步方法底层原理

  • 同步方法其实底层也是有隐式锁对象的,只是锁的范围是整个方法代码。
  • 如果方法是实例方法:同步方法默认用this作为的锁对象。但是代码要高度面向对象!
  • 如果方法是静态方法:同步方法默认用类名.class作为的锁对象。

方式三:Lock锁

在这里插入图片描述在这里插入图片描述

线程池

不使用线程池的问题 : 如果用户每发起一个请求,后台就创建一个新线程来处理,下次新任务来了又要创建新线程,而创建新线程的开销是很大的,这样会严重影响系统的性能。

在这里插入图片描述
在这里插入图片描述参数一:指定线程池的线程数量(核心线程): corePoolSize
相当于正式工
参数二:指定线程池可支持的最大线程数: maximumPoolSize
相当于员工总数,包含正式工和临时工
参数五:指定任务队列: workQueue
相当于座位总数(要服务的人需要有地方坐)
参数六:指定用哪个线程工厂创建线程: threadFactory
人力资源师,负责创建线程
参数七:指定线程忙,任务满的时候,新任务来了怎么办: handler
座位已满,新来的客人的处理方案

临时线程什么时候创建啊?
新任务提交时发现核心线程都在忙,任务队列(座位)也满了,并且还可以创建临时线程,此时才会创建临时线程。 (超负荷了才会招人)

什么时候会开始拒绝任务?
核心线程和临时线程都在忙,任务队列也满了,新的任务过来的时候才会开始任务拒绝。

举报

相关推荐

0 条评论