使用线程

 有三种使⽤线程的⽅法:

实现 Runnable 接⼝;

实现 Callable 接⼝;

继承 Thread 类。

实现 Runnable 和 Callable 接⼝的类只能当做⼀个可以在线程中运⾏的任务,不是真正意义上的线程, 因此最后还需要通过 Thread 来调⽤。可以理解为任务是通过线程驱动从⽽执⾏的。

 

实现 Runnable 接⼝

需要实现接⼝中的 run() ⽅法。

 

public class Main {

    public static void main(String[] args) {
        Runnable rn = new runn();

        Thread thre = new Thread(rn);
        thre.start();
        for (int i = 0; i < 10; i++) {
            System.out.println("zhu " + i);
        }
  
    }
}

class runn implements Runnable {
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("zi  " + i);
        }
    }
}

zi 0
zi 1
zhu 0
zi 2
zhu 1
zi 3
zhu 2
zi 4
zi 5
zi 6
zhu 3
zi 7
zhu 4
zi 8
zhu 5
zi 9
zhu 6
zhu 7
zhu 8
zhu 9

使⽤ Runnable 实例再创建⼀个 Thread 实例,然后调⽤ Thread 实例的 start() ⽅法来启动线程

实现 Callable 接⼝

与 Runnable 相⽐,Callable 可以有返回值,返回值通过 FutureTask 进⾏封装。

 Runnable 接口 不会返回结果或抛出检查异常,但是 Callable 接口 可以

工具类 Executors 可以实现将 Runnable 对象转换成 Callable 对象

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

public class Main {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<String> mc = new MyCallable();
        FutureTask<String> ft = new FutureTask<>(mc);
        Thread thread = new Thread(ft);
        thread.start();

        try {
            String s1 = ft.get(); // 等待保证一定线程执行完,才拿结果
            System.out.println("结果: " + s1);
        } catch (Exception e) {

            e.printStackTrace();
        }
    }
}

class MyCallable implements Callable<String> {
    public String call() throws Exception {
        String s = "";
        for (int i = 0; i < 3; i++) {
            s += Integer.toString(i);
        }
        return s;
    }
}

结果: 012

继承 Thread 类

同样也是需要实现 run() ⽅法,因为 Thread 类也实现了 Runable 接⼝。 当调⽤ start() ⽅法启动⼀个线程时,虚拟机会将该线程放⼊就绪队列中等待被调度,当⼀个线程被调度 时会执⾏该线程的 run() ⽅法。

 

public class Main {

    public static void main(String[] args) {
        Thread rn = new th();

        rn.start();
        for (int i = 0; i < 10; i++) {
            System.out.println("zhu  " + i);
        }
        // System.out.println(fu.get());
    }
}

class th extends Thread {
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("zi  " + i);
        }
    }
}

 

 

zi 0
zi 1
zhu 0
zi 2
zhu 1
zi 3
zhu 2
zhu 3
zi 4
zhu 4
zi 5
zhu 5
zhu 6
zi 6
zhu 7
zi 7
zhu 8
zi 8
zhu 9
zi 9

实现接⼝ VS 继承 Thread

实现接⼝会更好⼀些,因为: Java 不⽀持多重继承,因此继承了 Thread 类就⽆法继承其它类,但是可以实现多个接⼝; 类可能只要求可执⾏就⾏,继承整个 Thread 类开销过⼤

实现接口可以 多线程共享同一个实例

 

线程池 

https://www.zhihu.com/question/485071288

线程池其实是一种池化的技术的实现,池化技术的核心思想其实就是实现资源的一个复用,避免资源的重复创建和销毁带来的性能开销。在线程池中,线程池可以管理一堆线程,让线程执行完任务之后不会进行销毁,而是继续去处理其它线程已经提交的任务。

为什么要用线程池

    • 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
    • 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
    • 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控

 

创建线程池

 

 方式二:通过 Executor 框架的工具类 Executors 来实现

我们可以创建三种类型的 ThreadPoolExecutor:

 

 

《阿里巴巴 Java 开发手册》中强制线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险

线程池的构造其实很简单,就是传入一堆参数,然后进行简单的赋值操作。

 https://blog.csdn.net/qq_38408785/article/details/91383959?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-91383959-blog-122498816.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-91383959-blog-122498816.pc_relevant_default&utm_relevant_index=2

 常见的4种线程池

1、newCachedThreadPool:

/**
* 一个可缓存线程池,如果线程池长度超过需要处理需要,可灵活回收空闲线程,若无可回收,则新建线程
* 适合短时间的任务
* 缺点:要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。
*/
2、newFixedThreadPool:

/**
* 定长线程池,可以控制线程最大并发数,超出的任务会在队列中等待
* 缺点:要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。
*/
3、newScheduledThreadPool:

/**
* 定长的线程池,支持定时及周期性任务执行
* 缺点:问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。
*/
4、newSingleThreadExecutor

/**
* 单线程的线程池,保证所有任务先进先出来执行
* 缺点:要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。
*/

简述线程池的状态

  • Running:能接受新提交的任务,也可以处理阻塞队列的任务。
  • Shutdown:不再接受新提交的任务,但可以处理存量任务,线程池处于running时调用shutdown方法,会进入该状态。
  • Stop:不接受新任务,不处理存量任务,调用shutdownnow进入该状态。
  • Tidying:所有任务已经终止了,worker_count(有效线程数)为0。
  • Terminated:线程池彻底终止。在tidying模式下调用terminated方法会进入该状态。

线程池有哪些参数     7

corePoolSize 核心线程数

maximumPoolSize 最大线程数

keepAliveTime 空闲线程存活时间

unit 空闲线程存活时间单位

workQueue 工作队列

新任务被提交后,会先进入到此工作队列中,任务调度时再从队列中取出任务

threadFactory 线程工厂  创建一个新线程时使用的工厂,可以用来设定线程名、是否为daemon线程等等

handler 拒绝策略  

当工作队列中的任务已到达最大限制,并且线程池中的线程数量也达到最大限制,这时如果有新任务提交进来,该如何处理呢。这里的拒绝策略,就是解决这个问题的

 

 

 

执行 execute()方法和 submit()方法的区别

 execute执行流程

 

 

 

上图不准确

当前线程数目不小于核心线程数目 ,尝试放入阻塞队列 

如果小于最大线程数,那么也会创建非核心线程来执行提交的任务,如图

 

 

 从这里可以发现,就算队列中有任务,新创建的线程还是优先处理这个提交的任务,而不是从队列中获取已有的任务执行,从这可以看出,先提交的任务不一定先执行

jdk中提供了4中拒绝策略

①CallerRunsPolicy

该策略下,在调用者线程中直接执行被拒绝任务的run方法,除非线程池已经shutdown,则直接抛弃任务。

②AbortPolicy

该策略下,直接丢弃任务,并抛出RejectedExecutionException异常。

③DiscardPolicy

该策略下,直接丢弃任务,什么都不做。

④DiscardOldestPolicy

该策略下,抛弃进入队列最早的那个任务,然后尝试把这次拒绝的任务放入队列

线程池执行流程

 

 饱和策略 就是拒绝策略

https://blog.csdn.net/jisuanji12306/article/details/86363390?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-86363390-blog-114284804.pc_relevant_multi_platform_featuressortv2dupreplace&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-86363390-blog-114284804.pc_relevant_multi_platform_featuressortv2dupreplace&utm_relevant_index=2

 题目:有两个线程A、B,A线程向一个集合里面依次添加元素"abc"字符串,一共添加十次,当添加到第五次的时候,希望B线程能够收到A线程的通知,然后B线程执行相关的业务操作

import java.util.*;
import java.util.concurrent.locks.LockSupport;

public class Main {

    static volatile boolean notice = false;

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        Thread threadA = new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                list.add("aef");
                System.out.println("线程A向list中添加一个元素,此时list中的元素个数为:" + list.size());

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (list.size() == 5) {
                    notice = true;
                    System.out.println("a " + notice);
                }
            }
        });
        Thread threadB = new Thread(() -> {
            while (true) {
                // System.out.println("b " + notice);
                if (notice) {
                    System.out.println("线程B收到通知,开始执行自己的业务...");
                    break;
                }
            }
        });
        threadB.start();
        threadA.start();
    }
}

 

import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.LockSupport;

public class Main {

    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(1);
        List<String> list = new ArrayList<>();
        // 实现线程A
        Thread threadA = new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                list.add("abc");
                System.out.println("线程A向list中添加一个元素,此时list中的元素个数为:" + list.size());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (list.size() == 5) {
                    countDownLatch.countDown();
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        
        Thread threadB = new Thread(() -> {

            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("线程B收到通知,开始执行自己的业务...");

        });
        // 需要先启动线程B
        threadB.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 再启动线程A
        threadA.start();
    }

}

 

import java.util.*;
import java.util.concurrent.locks.LockSupport;

public class Main {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        // 实现线程B
        Thread threadB = new Thread(() -> {
            if (list.size() != 5) {
                LockSupport.park();
            }
            System.out.println("线程B收到通知,开始执行自己的业务...");
        });
        // 实现线程A
        Thread threadA = new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                list.add("abc");
                System.out.println("线程A向list中添加一个元素,此时list中的元素个数为:" + list.size());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (list.size() == 5)
                    LockSupport.unpark(threadB);
            }
        });

        threadA.start();
        threadB.start();

    }
}

 

 

 

Java并发编程-两个线程交替打印0-100的奇偶数

 

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

public class jiaoti {
    private static volatile int count = 0;
    private static final Object lock = new Object();
    private static final int num = 101;

    static class TurningRunner implements Runnable {

        @Override
        public void run() {

            while (count < num) {
                synchronized (lock) {
                    System.out.println(Thread.currentThread().getName() + ":" + count);
                    count++;
                    lock.notify(); // 唤醒另一个线程
                    if (count <= num) {
                        try {
                            lock.wait(); // 释放锁,进入阻塞状态,等待被唤醒
                        } catch (InterruptedException e) {
                            System.out.println(e.getMessage());
                        }
                    }
                }
            }

        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread th0 = new Thread(new TurningRunner(), "偶数");
        Thread th1 = new Thread(new TurningRunner(), "奇数");
        th0.start();

        // 短暂休眠,确保线程执行顺序
        Thread.sleep(50);
        th1.start();
        while (true) {

            if (count >= num) {
                th0.interrupt();
                th1.interrupt();
                break;
            }
        }

    }
}

 

 

public class jiaoti {
    private static int count = 0;
    private static final Object lock = new Object();
    private static final int num = 101;

    static class TurningRunner implements Runnable {

        @Override
        public void run() {

            while (count < num) {
                synchronized (lock) {
                    System.out.println(Thread.currentThread().getName() + ":" + count);
                    count++;
                    lock.notify(); // 唤醒另一个线程
                    if (count < num) {
                        try {
                            lock.wait(); // 释放锁,进入阻塞状态,等待被唤醒
                        } catch (InterruptedException e) {
                            System.out.println(e.getMessage());
                        }
                    }
                }
            }

        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread th0 = new Thread(new TurningRunner(), "偶数");
        Thread th1 = new Thread(new TurningRunner(), "奇数");
        th0.start();

        // 短暂休眠,确保线程执行顺序
        Thread.sleep(50);
        th1.start();

    }
}

 

给定两个数组,实现两个线程,交替循环打印

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

public class jiaoti {
    public static void main(String[] args) {
        char[] ai = "1234567".toCharArray();
        char[] ac = "ABCDEFG".toCharArray();
        Object obj = new Object();

        Thread t1 = new Thread(() -> {
            synchronized (obj) {
                for (char c : ai) {
                    System.out.print(c);
                    try {
                        obj.notify(); // 唤醒其它线程
                        obj.wait(); // 阻塞 t1
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                obj.notify();
            }
        });

        Thread t2 = new Thread(() -> {
            synchronized (obj) {
                for (char c : ac) {
                    System.out.print(c);
                    try {
                        obj.notify(); // 唤醒其它线程
                        obj.wait(); // 阻塞 t2
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                obj.notify();
            }
        });

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

 

posted on 2022-02-12 09:54  cltt  阅读(49)  评论(0编辑  收藏  举报

导航