1.什么时候用原子操作类,举个例子?
比如一个自增的操作就可以用原则操作类,原子操作类底层用的就是CAS。
2.什么时候用volitile,举个例子?
比如一个boolean的flag,因为它与上个状态无关。
3.手写程序,10个多线程保证 i从0加到10?
可以用原子操作类来实现
import java.util.concurrent.atomic.AtomicInteger;
public class Autoincrease {
public static void main(String[] args)
{
atomicThread matomicThread=new atomicThread();
for(int i=0;i<10;i++)
{
Thread thread=new Thread(matomicThread);
thread.start();
}
}
public static class atomicThread implements Runnable
{
public AtomicInteger i=new AtomicInteger();
@Override
public void run() {
while(true)
{
try {
Thread.sleep(1000);
}catch (Exception e)
{
e.printStackTrace();
}
System.out.println("线程: " + Thread.currentThread().getName() + "将数据变为: " + i.getAndIncrement());
}
}
}
}
4.如何避免死锁?
主要有三种方式:
参考:https://blog.csdn.net/ls5718/article/details/51896159?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-4&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-4
这篇文章对于死锁的讲解还是不错的
(1)加锁顺序
当多个线程需要相同的一些锁,但是按照不同的顺序加锁,死锁就很容易发生。
比如线程一lockA lockB线程二lockB lockA那么线程一占有A管线程二要B,但此时线程二占有B,它又去管线程一要A,这样就造成了死锁。如果要是都是一样的顺序的话,那么就可以避免死锁了。
按照顺序加锁是一种有效的死锁预防机制。但是,这种方式需要你事先知道所有可能会用到的锁(译者注:并对这些锁做适当的排序),但总有些时候是无法预知的。
(2)加锁时限
超时自动释放锁,就算发生死锁了,也会自动解开。
这种机制存在一个问题,在Java中不能对synchronized同步块设置超时时间。你需要创建一个自定义锁,或使用Java5中java.util.concurrent包下的工具。写一个自定义锁类不复杂,
(3)死锁检测
死锁检测是一个更好的死锁预防机制,它主要是针对那些不可能实现按序加锁并且锁超时也不可行的场景。
当发现死锁的时候,一个可行的做法是释放所有锁,回退,并且等待一段随机的时间后重试。一个更好的方案是给这些线程设置优先级,让一个(或几个)线程回退,剩下的线程就像没发生死锁一样继续保持着它们需要的锁。
5.公平锁与非公平锁的区别?
tryAcquire是公平锁和非公平锁实现的区别,两种类型的锁都是tryAcquire实现的。每一次的tryAcquire都会检查队列中是否仍有前驱的元素,如果仍然有那么继续等待,通过这种方式来保证先来先服务的原则;而非公平锁,首先是检查并设置锁的状态,这种方式会出现即使队列中有等待的线程,但是新的线程仍然会与排队线程中的对头线程竞争(但是排队的线程是先来先服务的),所以新的线程可能会抢占已经在排队的线程的锁,这样就无法保证先来先服务,但是已经等待的线程们是仍然保证先来先服务的。
公平锁能保证:老的线程排队使用锁,新线程仍然排队使用锁。
非公平锁保证:老的线程排队使用锁;但是无法保证新线程抢占已经在排队的线程的锁。
6.synchronized与Lock的区别?
synchronized是一个关键字,可重入,不可判断锁的状态,非公平,自动释放锁。
Lock是一个类,可重入,可判断锁的状态,可公平也可非公平(默认非公平,可构造的时候在ReentrantLock中加入true参数),必须主动释放锁。