JUC基础入门

126 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第4天,点击查看活动详情

前置知识

JUC是什么?

java.util.concurrent的简称,是java5开始提供的并发编程的工具类

进程是什么?

进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体

所以进程是操作系统分配资源的最小单位,是一个可运行程序的实例,是线程的容器

shift + alt + esc打开任务管理器,就能看到当前系统正在运行的一排排进程了

线程是什么?

线程(Thread)是操作系统能够进行运算调度的最小单位。大部分情况下,它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。

(Linux下没有真正的线程,只有LWP,但Windows是有的哦)

所以线程是操作系统能调度的最小单位,可以共享进程中的全部资源,一个进程可以同时并行多条线程

Java线程的状态

打开Thread.State枚举类

public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,

        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
        RUNNABLE,

        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
        BLOCKED,

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * is waiting for a specified thread to terminate.
         */
        WAITING,

        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
        TERMINATED;
    }
  • NEW 线程创建但未启动的状态
  • RUNNABLE 处于可运行的状态
  • BLOCKED 阻塞状态
  • WAITING 等待状态
  • TIMED-WAITING 具有指定等待时间的等待线程的线程状态
  • TERMINATED 终止状态

wait和sleep的区别

  • 调用方式 wait是Object的对象方法,Sleep是线程类Thread的静态方法
  • 是否会释放当前锁 sleep会不会释放当前线程占有的锁,如果wait在同步块/方法内则会释放锁

并发和并行的区别

并发就是多个线程去使用同一个资源
并行是多个线程同时工作再汇总

管程是什么?

就是锁(Lock) 操作系统中,有两种方法来实现锁机制, 分别是信号量(Semaphere)和管程(Minitor),JDK中的就是通过管程实现的

用户线程和守护线程有什么区别?

都可以通过用户创建与使用,区别是守护线程随主线程结束而结束,而用户线程的生命周期和主线程不同步

Thread类提供了两个对象方法来设置或判断守护线程

    public final void setDaemon(boolean on) {
        checkAccess();
        if (isAlive()) {
            throw new IllegalThreadStateException();
        }
        daemon = on;
    }

    public final boolean isDaemon() {
        return daemon;
    }

同步代码块/方法与锁

synchronizad 可以作用于一段代码块上,一个方法上等,本质是同步锁 当一个线程获得该同步锁时,其他试图访问该对象的线程将被阻塞,这个基础就不再多讲了,不会的同学可以去看看基础教程

卖票例子

    class Ticket {
        private int ticket = 50;

        public synchronized void sale() {
            if (ticket > 0) {

                System.out.println(Thread.currentThread().getName() + "::" + ticket--);
            }
        }
    }

    @Test
    public void sale() {
        Ticket ticket = new Ticket();
        Runnable runnable = () -> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        };
        new Thread(runnable, "t3").start();
        new Thread(runnable, "t1").start();
        new Thread(runnable, "t2").start();

    }

Lock接口提供了比synchronizad更广泛的锁定操作

需要手动上锁以及释放锁

锁类型:

  • ReentrantLock 可重入锁
  • ReentrantReadWriteLock.ReadLock
  • ReentrantReadWriteLock.WeriteLock

卖票例子2

        public synchronized void sale() {
            lock.lock();
            if (ticket > 0) {
                System.out.println(Thread.currentThread().getName() + "::" + ticket--);
            }
            lock.unlock();
        }

线程通信wait,notify/notifyAll

        public synchronized void incr() throws InterruptedException {
            while (num != 0) {
                this.wait();
            }
            num++;
            System.out.println(Thread.currentThread().getName()+"::"+num);
            this.notifyAll();
        }

wait方法可能会有虚假唤醒的可能,因为在哪里沉睡就会在哪里醒来,所以if判断只会执行一次,所以要用while()包裹,源码注释如下:

As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop:
      synchronized (obj) {
          while (<condition does not hold>)
              obj.wait();
          ... // Perform action appropriate to condition
      }