分享java多线程学习笔记

Java多线程基础知识,面试足以。

一、线程状态:

1.new 初始
2.runnable 运行
3.blocked 阻塞
4.waiting 等待
5.time_waiting 超时等待
6.terminated 终止
在这里插入图片描述

二、创建线程方式:

1.继承Thread,重写父类run方法。
2.实现Runable接口,并实现run方法。
3.线程池Executors.newSingleThreadExecutor();
  通过线程工厂newThread方法新建线程,实际为new Thread();

三、线程挂起、唤醒:

1.thread.suspend() -----旧版本废弃
 thread.resume() -----旧版本废弃
 会造成线程挂起,不会释放锁,造成死锁
2.wait() 暂停执行、放弃以获取的锁进入等待状态
 notify() 随机唤醒一个在等待的线程
 notifyAll() 唤醒所有在等待的线程。

四、线程中断

1.thread.stop(); 线程立刻终止,线程不安全。
2.thread.interrupt(); 自定义线程中断状态,不会立刻中断线程,设置该线程的中断状态位,即设置中断状态为true。
 使用Thread.currentThread().isInterrupted()判断线程是否被中断
 判断某个线程是否已被发送过中断请求,使用Thread.currentThread().isInterrupted()方法(因为它将线程中断标示位设置为true后,不会立刻清除中断标示位,即不会将中断标设置为false),而不要使用thread.interrupted()(该方法调用后会将中断标示位清除,即重新设置为false)方法来判断,下面是线程在循环中时的中断方式:

while(!Thread.currentThread().isInterrupted() && more work to do){
    do more work
}

 使用thread.interrupt(); 如何中断线程
 如果一个线程处于了阻塞状态(如线程调用了thread.sleep、thread.join、thread.wait、1.5中的condition.await、以及可中断的通道上的 I/O 操作方法后可进入阻塞状态),则在线程在检查中断标示时如果发现中断标示为true,则会在这些阻塞方法(sleep、join、wait、1.5中的condition.await及可中断的通道上的 I/O 操作方法)调用处抛出InterruptedException异常,并且在抛出异常后立即将线程的中断标示位清除,即重新设置为false。抛出异常是为了线程从阻塞状态醒过来,并决定线程是否真的需要中断。

public class ThreadIntepurt extends Thread{
    public static void main(String args[]) throws Exception {
        ThreadIntepurt thread = new ThreadIntepurt();
        System.out.println("Starting thread...");
        thread.start();
        Thread.sleep(3000);
        System.out.println("Asking thread to stop...");
        thread.interrupt();// 等中断信号量设置后再调用
        Thread.sleep(3000);
        System.out.println("Stopping application...");
    }
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            System.out.println("Thread running...");
            try {
                /*
                 * 如果线程阻塞,将不会去检查中断信号量stop变量,所 以thread.interrupt()
                 * 会使阻塞线程从阻塞的地方抛出异常,让阻塞线程从阻塞状态逃离出来,并
                 * 进行异常块进行 相应的处理
                 */
                Thread.sleep(1000);// 线程阻塞,如果线程收到中断操作信号将抛出异常
            } catch (InterruptedException e) {
                System.out.println("Thread interrupted...");
                /*
                 * 如果线程在调用 Object.wait()方法,或者该类的 join() 、sleep()方法
                 * 过程中受阻,则其中断状态将被清除
                 */
                System.out.println(this.isInterrupted());// false
                //中不中断由自己决定,如果需要真真中断线程,则需要重新设置中断位,如果
                //不需要,则不用调用
//                Thread.currentThread().interrupt();
            }
        }
        System.out.println("Thread exiting under request...");
    }
}

五、线程优先级、守护线程

1. 线程优先级
 java定义线程的优先级为1-10,默认值为5,最大值为10。“高优先级线程”被CPU分配的概率高于“低优先级线程”,但是无论是是级别相同还是不同,线程调用都不会绝对按照优先级执行,每次执行结果都不一样,调度算法无规律可循,所以线程之间不能有先后依赖关系。

   // 新建t1
    Thread t1=new Thread(()->{
          System.out.println("thread1");
      },"thread1");
      // 新建t2
      Thread t2=new Thread(()->{
          System.out.println("thread2");
      },"thread2");
      t1.setPriority(Thread.MIN_PRIORITY); //设置最小优先级
      t2.setPriority(Thread.MAX_PRIORITY);//设置最打优先级

2. 守护线程
 在Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程) 。
  当JVM中只要有非守护线程运行,守护线程就回持续工作,只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。

Thread daemonTread = new Thread();
daemonThread.setDaemon(true);//设置为守护线程

JVM中守护线程最典型的应用就是 GC (垃圾回收器),它就是一个很称职的守护者。

六、线程安全性问题

成因:

1)多线程环境
2)多个线程操作同一共享资源
3)对该共享资源进行非原子性操作

如何避免:

打破成因成任意一点即可避免。
1:多线程环境改为单线程(必要的代码加锁访问);
2:多个线程访问同一资源- -不共享资源(ThreadLocal、不共享、操作 无状态化、共享资源不可变);
3:对共享资源进行非原子性操作- - 将非原子性操作改成原子性操作(加锁、使用JDK自带的原子性操作的类、JUC提供的相应的并发工具类)。

七、原子性操作

一个操作或者多个操作,要么全部执行并且执行过程不会被任何元素打断,要么就不执行。

八.深入理解synchronized

1)内置锁

每个java对象都可以做一个实现同步锁,这些所被称内置锁。线程进入代码块或者方法的时候会自动获取该锁,在退出同步代码块或者方法的时候会释放该锁。
获得内置锁的唯一途径就是进入这个锁保护的同步代码块或方法。

2)互斥锁

内置锁是一个互斥锁,这就是意味这最多只有一个线程能够获得该锁,当线程A尝试去获取线程B持有的内置锁时,线程A必须等待或者阻塞,直到线程B释放这个锁,如果线程B不释放这个锁,线程A将一直等待下去。

3)修饰普通方法

锁住类的实例。

4)修饰静态方法

锁住类。

5)修饰代码块

锁住一个对象,synchronized(lock) 括号内的内容。

九、深入理解lock接口

lock是一个接口,内部提供6中方法。

  1. lock():lock()方法是平常使用得最多的一个方法,就是用来获取锁。如果锁已被其他线程获取,则进行等待。
  2. tryLock():有返回值的,它表示用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false,也就说这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待。
  3. tryLock(long time, TimeUnit unit):和tryLock()方法是类似的,只不过区别在于这个方法在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false。如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回true。
  4. lockInterruptibly():当通过这个方法去获取锁时,如果线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态。也就使说,当两个线程同时通过lock.lockInterruptibly()想获取某个锁时,假若此时线程A获取到了锁,而线程B只有在等待,那么对线程B调用threadB.interrupt()方法能够中断线程B的等待过程。
  5. unlock():释放锁,一般需要加锁的资源(临界区)需要放到try中,而unlock()要放到finally中。
  6. newCondition():获取新的条件,可精准控制线程,取代Object监视器方法( wait , notify和notifyAll )。

十、synchronized和Lock锁区别

  1. synchronized是java关键字,lock是一个对象。
  2. synchronized无法判断是否获取锁的状态,Lock可以判断是否能获取到锁(tryLock() 方法)。
  3. synchronized是自动释放锁(a线程在执行完毕后释放锁,b线程执行过程中发生异常也会自动释放锁),lock需要放在finally中手动释放锁,否则容易造成死锁。
  4. synchronized无法中断等待线程(a 线程如果阻塞了,b线程需要一直等待),lock可以自定义控制b线程是否需要等待。
  5. synchronized的锁可重入,非公平,不可中断,Lock锁可重入,可判断是否公平,可中断。
  6. Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。

-----------------------------------------2021.3.15 11点更新至此-----------------------------

八、volatile关键字

十一、读写锁ReentrantReadWriteLock

十二、StampedLock原理及使用

十三、wait、notify、notifyAll

十四、线程之前通讯

十五.Condition

十六、容器

十七、并发工具类

1.CountDownLatch
2.CyclicBarrier -----栅栏
3.Semaphore—信号量
4.Exchanger

十八、线程池

十九、Future与Callable、FutureTask

二十、线程池核心组成及运行机制

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值