java多线程-JUC

JUC之java高并发-多线程学习

1. JUC定义

源码 + 官方文档
在这里插入图片描述

java.util工具包下的三个接口及工具类

**业务:**普通的线程代码:Thread

**Runnable接口:**没有返回值、效率相比于Callable较低

在这里插入图片描述

在这里插入图片描述

2. 线程和进程

线程、进程使用一句话来概括

**进程:**一个程序,如QQ.exe,Music.exe程序的集合

  • 一个进程往往可以包含多个线程,至少会包含一个!
  • java默认有两个线程:mainGC

**线程:**比如当前开启了一个Typora进程,在其中进行打字,保存,删除等单一操作是由特定的线程负责的

  • java实现线程:ThreadRunnableCallable

Java程序真的可以开启线程吗?看源码!

/**
     * Causes this thread to begin execution; the Java Virtual Machine
     * calls the <code>run</code> method of this thread.
     * <p>
     * The result is that two threads are running concurrently: the
     * current thread (which returns from the call to the
     * <code>start</code> method) and the other thread (which executes its
     * <code>run</code> method).
     * <p>
     * It is never legal to start a thread more than once.
     * In particular, a thread may not be restarted once it has completed
     * execution.
     *
     * @exception  IllegalThreadStateException  if the thread was already
     *               started.
     * @see        #run()
     * @see        #stop()
     */
public synchronized void start() {
   
    /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
    if (threadStatus != 0)
        throw new IllegalThreadStateException();

    /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
    group.add(this);

    boolean started = false;
    try {
   
        start0();
        started = true;
    } finally {
   
        try {
   
            if (!started) {
   
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {
   
            /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
        }
    }
}

private native void start0();
  • 注意看start0()方法,是使用native关键字修饰的,这个是本地方法,不是java程序完成的,是别的C/C++程序操作的,因为java程序必须执行在JVM环境中,无法直接操作计算机硬件,所以创建线程本质上并非java程序完成!

并发、并行的区别

并发编程:并发并行

并发:(多线程操作同一资源)

  • CPU一核,模拟出来多条线程,通过快速交替执行来达到并发的目的

并行:(多个线程同时执行)

  • CPU多核,多个线程可以同时执行;线程池

在这里插入图片描述

并发编程的本质:充分利用CPU的资源!

线程的几个状态

/**
     * A thread state.  A thread can be in one of the following states:
     * <ul>
     * <li>{@link #NEW}<br>
     *     A thread that has not yet started is in this state.
     *     </li>
     * <li>{@link #RUNNABLE}<br>
     *     A thread executing in the Java virtual machine is in this state.
     *     </li>
     * <li>{@link #BLOCKED}<br>
     *     A thread that is blocked waiting for a monitor lock
     *     is in this state.
     *     </li>
     * <li>{@link #WAITING}<br>
     *     A thread that is waiting indefinitely for another thread to
     *     perform a particular action is in this state.
     *     </li>
     * <li>{@link #TIMED_WAITING}<br>
     *     A thread that is waiting for another thread to perform an action
     *     for up to a specified waiting time is in this state.
     *     </li>
     * <li>{@link #TERMINATED}<br>
     *     A thread that has exited is in this state.
     *     </li>
     * </ul>
     *
     * <p>
     * A thread can be in only one state at a given point in time.
     * These states are virtual machine states which do not reflect
     * any operating system thread states.
     *
     * @since   1.5
     * @see #getState
     */
    public enum State {
   
        // 创建
        NEW,
		// 运行
        RUNNABLE,
		// 阻塞
        BLOCKED,
		// 等待-一直等待
        WAITING,
		// 超时等待-限制时间(过时不候)
        TIMED_WAITING,
		// 销毁
        TERMINATED;
    }

wait/sleep的区别

1. 来自不同的类

wait() ==>>> Object类 sleep() ==>>> Thread类

2. 关于锁的释放

wait会释放锁,sleep如同人睡着了,忘记释放锁的操作!

3.使用的范围不同

wait ==>>> 同步代码块 sleep ==>>> 任意地方

4.异常捕获

二者都需要进行中断异常捕获!

3. Lock锁(重点)

传统的synchronized

Lock

在这里插入图片描述

在这里插入图片描述

公平锁:十分公平,先来先得

非公平锁:十分不公平:可以插队(默认)

Synchronized锁和Lock锁的区别

1. Synchronized是内置的java关键字,Lock是一个java接口

2. Synchronized无法判断获取锁的状态,Lock可以判断是否获取到了锁;

3. Synchronized会自动释放锁,Lock必须要手动释放锁,如果不释放锁,就会产生死锁;

4. Synchronized 线程(获取锁时会进入阻塞状态)、其余线程只能一直等待当前线程释放锁;Lock可以尝试获取当前锁,未必会一直等待下去;

5. Synchronized 可重入锁,不可以中断,为非公平锁;Lock为可重入锁,可以判断锁的状态,默认为非公平锁,但可以自行设置;

6. Synchronized 适合锁少量代码同步问题,Lock适合锁大量的同步代码块。

锁是什么?如何判断锁的对象是谁?

4. 生产者和消费者问题

面试程序:单例模式、八大排序算法、生产者和消费者、死锁

Synchronized wait notify版本为老版本!

问题存在,A、B两个线程执行没有任何问题;A、B、C、D多线程同时启动,还能保证线程同步吗?—虚假唤醒

在这里插入图片描述

  • 解决:将if单词判断修改为循环判断

JUC版本的生产者和消费者问题,话不多说,见JDK源码:

class BoundedBuffer {
   
   final Lock lock = new ReentrantLock();
   final Condition notFull  = lock.newCondition(); 
   final Condition notEmpty = lock.newCondition(); 

   final Object[] items = new Object[100];
   int putptr, takeptr, count;

   public void put(Object x) throws InterruptedException {
   
     lock.lock(); try {
   
       while (count == items.length)
         notFull.await();
       items[putptr] = x;
       if (++putptr == items.length) putptr = 0;
       ++count;
       notEmpty.signal();
     } finally {
    lock.unlock(); }
   }

   public Object take() throws InterruptedException {
   
     lock.lock(); try {
   
       while (count == 0)
         notEmpty.await();
       Object x = items[takeptr];
       if (++takeptr == items.length) takeptr = 0;
       --count;
       notFull.signal();
       return x;
     } finally {
    lock.unlock(); }
   }
 } 
  • Synchronized版本 : wait()方法 || notify()方法
  • Lock版本 : await()方法 || signal()方法

Condition接口的优势在什么地方?— 精准通知和唤醒线程

5. 8锁现象-解决判断锁的对象问题

对象–>多个/class–>唯一

  • 8锁之问题一--->>标准情况下,两个线程是发短信先进行,还是打电话先进行(先执行发短信,再执行打电话)
    
  • 八锁问题之二--->>增加了非同步方法后,线程执行不受锁的影响(先执行非同步方法);
    * 两个对象,两个同步方法,谁先执行,就先有锁锁住方法调用者,没有延迟的先执行
    
  • 八锁问题之三--->>增加两个静态同步方法,静态方法在类加载就产生,为.class模板,一个类中的所有静态方法使用的是同一个
    * Class模板,所以static方法会顺序执行,无论有多少个对象进行方法调用
    
  • 八锁问题之四--->>一个普通的同步方法和一个静态的同步方法,在一个对象进行调用时;
    * 一个普通的同步方法和一个静态的同步方法,在两个对象进行调用时;我的都是先执行静态同步方法
    

小结

  • new出来的实例,this关键字可修饰,是一个类的具体实例;

  • static Class模板,是一个类的唯一模板

6. 集合类不安全

List不安全

  • 会造成ConcurrentModificationException并发修改异常!

解决方案如下:

1、List<String> list = new Vector<>();
2、List<String> list = Collections.synchronizedList(new ArrayList<>());
3、List<String> list = new CopyOnWriteArrayList<>(); 因为Vector中读写方法都为同步方法,在执行效率方面不如CopyOnWriteArrayList的非同步方法效率高,CopyOnWriteArrayList中使用的是Lock锁,对锁的状态操作比较灵活

Set不安全

在这里插入图片描述

解决方案如下:

1、Set<String> set = Collections.synchronizedSet(new HashSet<>()); 请爸爸来帮忙
2、Set<String> set = new CopyOnWriteArraySet<>();
  • hashSet底层是什么?
/**
  * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
  * default initial capacity (16) and load factor (0.75).
 **/
public HashSet() {
   
    map = new HashMap<>();
}
/**
  * add方法 set 的底层本质就是map, hashmap中key是无法重复的
 **/
public boolean add(E e) {
   
    return map.put(e, PRESENT)==null;
}

// Dummy value to associate with an Object in the backing Map
private static final Object PRES
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值