likes
comments
collection
share

多线程相关

作者站长头像
站长
· 阅读数 3

1.java中创建线程的方式

继承thread类,重写run()方法 实现runable接口,重写run()方法,避免了单继承的局限性 实现callable接口,重写call()方法,这个有放回值

2.线程的几种状态

线程在一定条件下,状态会发生变化。线程一共有以下几种状态:

1、新建状态(New) :新创建了一个线程对象。

2、就绪状态(Runnable) :线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于“可运行线程池”中,变得可运行,只等待获取CPU的使用权即在就绪状态的进程除 CPU之外,其它的运行所需资源都已全部获得。

3、运行状态(Running): 就绪状态的线程获取了CPU,执行程序代码。

4、阻塞状态(Blocked): 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。

阻塞的情况分三种:

(1)、等待阻塞:运行的线程执行wait()方法,该线程会释放占用的所有资源,JVM会把该线程放入“等待池” 中。进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用notify()或notifyAll()方法才能被唤醒,

(2)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入 “锁池” 中。

(3)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

5、死亡状态(Dead): 线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

3.谈谈线程死锁,如何有效的避免线程死锁?

运行两个或多个线程时,由于同时持有相互需要的锁对象,造成线程进入阻塞状态,谁都无法继续继续,造成死锁

避免造成死锁,1是尽量不要使用嵌套锁,2是使用定时锁 ReentrantLock

4.如何实现多线程中的同步

synchronized (同步非静态方法或同步代码块,同步的静态方法会锁住整个类) lock(lock unlock,必须在finally里调用unlock()释放锁,否则会造成死锁) volatile a.volatile关键字为域变量的访问提供了一种免锁机制,

    b.使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新,

    c.因此每次使用该域就要重新计算,而不是使用寄存器中的值

    d.volatile不会提供任何原子操作,它也不能用来修饰final类型的变量

//需要同步的变量加上volatile

            private volatile int account = 100;

5.synchronized和Lock的使用、区别,原理;

使用见问题四 区别: 1.sync时关键字,lock是接口 2.在线程异常时,sync会自动释放锁,不会因此导致死锁,而lock不会自动释放锁,必须在finally手动释放(unlock),不然可能会导致死锁 3.通过lock可以知道有没有获取成功锁(trylock()方法),sync办不到 4.Lock可以提高多个线程进行读操作的效率。 5.在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。

6.volatile,synchronized和volatile的区别?为何不用volatile替代synchronized?

vilatile,是关键字,为了让变量在发生改变时尽快让其他线程知道

原理:当对volatile标记的变量进行修改时,会将其他缓存中存储的修改前的变量清除,然后重新读取。一般来说应该是先在进行修改的缓存A中修改为新值,然后通知其他缓存清除掉此变量,当其他缓存B中的线程读取此变量时,会向总线发送消息,这时存储新值的缓存A获取到消息,将新值穿给B。最后将新值写入内存。当变量需要更新时都是此步骤,volatile的作用是被其修饰的变量,每次更新时,都会刷新上述步骤。

区别:synchronized 是独占锁/排他锁(就是有你没我的意思),同时只能有一个线程调用 add10KCount 方法,其他调用线程会被阻塞。所以三行 CPU 指令都是同一个线程执行完之后别的线程才能继续执行,这就是通常说说的 原子性 (线程执行多条指令不被中断)

但 volatile 是非阻塞算法(也就是不排他),当遇到三行 CPU 指令自然就不能保证别的线程不插足了,这就是通常所说的,volatile 能保证内存可见性,但是不能保证原子性

什么时候用volatile:如果写入变量值不依赖变量当前值,那么就可以用 volatile

volatile 和 synchronized 的区别?

  1. volatile 本质是在告诉 JVM 当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取。synchronized 则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
  2. volatile 仅能使用在变量级别。synchronized 则可以使用在变量、方法、和类级别的。
  3. volatile 仅能实现变量的修改可见性,不能保证原子性。而synchronized 则可以保证变量的修改可见性和原子性。
  4. volatile 不会造成线程的阻塞。synchronized 可能会造成线程的阻塞。
  5. volatile 标记的变量不会被编译器优化。synchronized标记的变量可以被编译器优化。

另外,会有面试官会问 volatile 能否取代 synchronized 呢?答案肯定是不能,虽然说 volatile 被称之为轻量级锁,但是和 synchronized 是有本质上的区别,原因就是上面的几点落。

什么场景下可以使用 volatile 替换 synchronized ?

  1. 只需要保证共享资源的可见性的时候可以使用 volatile 替代,synchronized 保证可操作的原子性一致性和可见性。
  2. volatile 适用于新值不依赖于旧值的情形。
  3. 1 写 N 读。
  4. 不与其他变量构成不变性条件时候使用 volatile 。

7.锁的分类,锁的几种状态

可重入锁(sync和lock) 可中断锁(lock,如果不想等了可以中断去做其他的事) 公平锁(ReentrantLock 尽量以请求锁的顺序来获取所) 读写锁(ReentrantReadWriteLock 可以多个线程读一个线程写)

锁一共有4种状态,级别从低到高依次是:无锁,偏向锁,轻量级锁,重量级锁。锁只能逐一升级,不能降级。重量级锁

8.sleep()与wait()区别,run和start的区别,notify和notifyall区别,锁池,等待池

sleep是thread的静态方法,wait是object的方法 sleep会让出cpu调度,但是会保留锁,时间到了之后继续执行 wait会释放锁,进入等待池等待唤醒,只有notify或notify all的时候才会重新唤醒

start是线程启动,run是执行线程体 start只能调用1次,多次调用会抛异常,而run没有限制

notify是随机唤醒唤醒一个wait线程,进入锁池,而notify all是唤醒等待池里的所有wait线程

9.java中线程通信机制

同步(sync) while轮询方式(比较耗费资源) wait/notify方式

10.为什么java使用线程池

当我们需要的并发执行线程数量很多时,且每个线程执行很短的时间就结束了,这样,我们频繁的创建、销毁线程就大大降低了工作效率(创建和销毁线程需要时间、资源)。 java中的线程池可以达到这样的效果:一个线程执行完任务之后,继续去执行下一个任务,不被销毁,这样线程利用率提高了。。

11.Java中的线程池参数,共有几种

多线程相关

转载自:https://juejin.cn/post/7035599110807748638
评论
请登录