ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

并发基础知识

2021-08-03 19:03:48  阅读:124  来源: 互联网

标签:Thread class 基础知识 并发 线程 products LOGGER public


线程的概念

进程是系统进行资源分配和调度的基本单位,线程则是进程的一个执行路径,一个进程中至少有一个线程,进程中的多个线程共享进程的资源。真正占用 CPU 的是线程,线程是 CPU 分配的基本单位。

Java 经常以 Main 函数作为程序执行的入口,Main 函数所在的线程就是进程中的一个线程,一般称为主线程。在 Java 中多个线程共享进程的堆和方法区,但是每个线程有自己的程序计数器和栈。

线程创建的方式

  • 继承 Thread 方式
    public class ThreadStudy extends Thread {
        @Override
        public void run() {
            System.out.println(Thread.currentThread.getName());
      }
    }
    // 启动方式
    Thread threadStudy = new ThreadStudy();
    threadStudy.start();
  • 实现 Runnable 接口方式
    public class RunnableTaskStudy implements Runnable {
        @Override
        public void run() {
            System.out.println(Thread.currentTread.getName());
      }
    }
    // 启动方式
    RunnableTaskStudy taskStudy = new RunnableTaskStudy();
    Thread thread1 = new Thread(taskStudy);
    Thread thread2 = new Thread(taskStudy);
    thread1.start();
    thread2.start();
  • 实现 Callable 接口,该方式可以获取返回值
    public class CallableTaskStudy implements Callable<String> {
        @Override
        public void call() throws Exception {
            return "hello";
        }
    }

    // 启动
    FutureTask<String> futureTask = new FutureTask<>(new CallableStudy());
    Thread thread = new Thread(futureTask);
    thread.start();
    try {
        String result = futureTask.get();
        LOGGER.info("Result is " + result);
    } catch (InterruptedException | ExecutionException e) {
        LOGGER.info(e.getMessage());
        throw e;
    }

线程通知与等待

  • 当一个线程调用一个共享变量的 wait() 方法后,该线程被阻塞挂起,直到下面几件事情发生返回:
    1. 其它线程调用了该共享变量的 notify(), notifyAll() 方法。
    2. 其它线程调用了该线程的 interrupt() 方法,该线程抛出 InterruptedException 异常后返回。

    调用共享变量的 wait() 方法前,必须先获取该共享变量的监视器锁。

  • 一个线程调用了共享变量的 notify() 方法时后,会唤醒一个在该共享变量上调用 wait() 系列方法后被挂起的线程

    被唤醒的线程不能马上从 wait() 方法返回并继续执行,它必须在获取了共享变量的监视器锁之后才可以返回。

  • 代码实现

    代码实现需要注意的地方是在判断是否满足执行条件时需要使用 while 循环来防止虚假唤醒

    static class PurchaseThread extends Thread {
        private static final Logger LOGGER = Logger.getLogger(PurchaseThread.class.toString());

        private final Resource resource;

        public PurchaseThread(Resource resource) {
            this.resource = resource;
        }

        @Override
        public void run() {
            try {
                resource.purchase();
            } catch (InterruptedException exp) {
                LOGGER.severe(exp.getMessage());
            }
        }
    }

    static class SaleThread extends Thread {
        private static final Logger LOGGER = Logger.getLogger(SaleThread.class.toString());

        private final Resource resource;

        public SaleThread(Resource resource) {
            this.resource = resource;
        }

        @Override
        public void run() {
            try {
                resource.sale();
            } catch (InterruptedException exp) {
                LOGGER.severe(exp.getMessage());
            }
        }
    }

    static class Resource {
        private static final Logger LOGGER = Logger.getLogger(Resource.class.toString());

        private static final int MAX_SIZE = 10;

        private final Deque<String> products;

        public Resource(Deque<String> products) {
            this.products = products;
        }

        public void purchase() throws InterruptedException {
            synchronized (products) {
                while (products.size() == MAX_SIZE) {
                    products.wait();
                }
                while (products.size() < MAX_SIZE) {
                    products.addLast(UUID.randomUUID().toString());
                }
                products.notifyAll();
            }
        }

        public void sale() throws InterruptedException {
            synchronized (products) {
                // 这里需要通过while循环来防止虚假唤醒,如果这里使用if作为判断,当线程醒来之后就直接执行后面的逻辑了
                while (products.size() == 0) {
                    products.wait();
                }
                LOGGER.info(products.removeLast());
                products.notifyAll();
            }
        }
    }

线程中断

  • interrupt() 方法

    A 线程可以调用 B 线程的 interrupt() 方法来将 B 线程的中断标志位设置为 true 并返回,这里并不会影响 B 线程的执行。如果 B 调用了 wait() 系列函数,join() 方法,sleep() 方法而被挂起,这个时候 A 调用 B 线程的 interrupt() 方法,线程 B 会在调用方法出抛出 InterruptedException 异常并返回。

  • isInterrupted()

    检测当前线程是否被中断

  • interrupted()

    检测当前线程被中断,如果当前线程被中断,则清除中断标志位。

  • 代码实现
    static class PrintThread extends Thread {
        private static final Logger LOGGER = Logger.getLogger(PrintThread.class.toString());

        @Override
        public void run() {
            while (!Thread.currentThread().isInterrupted()) {
                LOGGER.info("Print Yes");
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException exp) {
                    // 当休眠时被中断会抛出中断异常
                    LOGGER.severe(exp.getMessage());
                    break;
                }
            }
        }
    }

    PrintThread thread = new PrintThread();
    thread.start();
    TimeUnit.SECONDS.sleep(1);
    // 这里中断线程
    thread.interrupt();
    LOGGER.info("Main thread is over.");

标签:Thread,class,基础知识,并发,线程,products,LOGGER,public
来源: https://www.cnblogs.com/sparkchan/p/15095499.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有