java的多线程学习,第五记
死锁问题;
public class DeadLock { //锁的嵌套 会出现死锁 //1 尽量不要去写锁嵌套 //2 private static Object locka = new Object(); private static Object lockb = new Object(); public static void main(String[] args) { new DeadLock().deadLock(); } private void deadLock() { Thread thread1 = new Thread(new Runnable() { @Override public void run() { synchronized (locka){ try { System.out.println(Thread.currentThread().getName()+"获取A锁 ing~!"); Thread.sleep(500); System.out.println(Thread.currentThread().getName()+"睡眠 500ms!"); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"需要B锁!!!"); synchronized (lockb){ System.out.println(Thread.currentThread().getName()+"B锁中!!!"); } } } },"thread1"); Thread thread2 = new Thread(new Runnable() { @Override public void run() { synchronized (lockb){ try { System.out.println(Thread.currentThread().getName()+"获取B锁 ing~!"); Thread.sleep(500); System.out.println(Thread.currentThread().getName()+"睡眠 400ms!"); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"需要A锁!!"); synchronized (locka){ System.out.println(Thread.currentThread().getName()+"A锁中!"); } } } },"thread2"); thread1.start(); thread2.start(); } }
锁的嵌套 会出现死锁
1 尽量不要去写锁嵌套
2 锁嵌套的顺序
3 引入超时机制
显示锁ReentrantLock可重入的锁,我自己的锁可以多次进入。而sync是在jvm层面的。
public class LockTest1 { Lock lock = new ReentrantLock(); private static Object locka = new Object(); private static Object lockb = new Object(); public static void main(String[] args) { new LockTest1().deadLock(); } private void deadLock() { Thread thread1 = new Thread(new Runnable() { @Override public void run() { getLock(); } },"thread1"); Thread thread2 = new Thread(new Runnable() { @Override public void run() { getLock(); } },"thread2"); thread1.start(); thread2.start(); } public void getLock(){ try{ lock.lock(); System.out.println(Thread.currentThread().getName()+"获取A锁 ing~!"); Thread.sleep(500); System.out.println(Thread.currentThread().getName()+"睡眠 500ms!"); }catch (InterruptedException e){ e.printStackTrace(); }finally { lock.unlock(); } } }
显示锁ReentrantLock可重入的锁,我自己的锁可以多次进入。而sync是在jvm层面的。
lock.lock()方法是上锁,然后还有在finally里面解锁。这个unlock()方法可能是会锁死的。
或者,用trylock()方法。
if(lock.tryLock(300, TimeUnit.MILLISECONDS)){ System.out.println(Thread.currentThread().getName()+"获取A锁 ing~!"); Thread.sleep(500); System.out.println(Thread.currentThread().getName()+"睡眠 500ms!"); }else{ //记录日志 System.out.println("获取锁失败!"); }
引入超时机制。还有中断锁lockInterruptibly()。
如果某一线程A正在执行锁中的代码,另一个线程B正在等待获取该锁,可能由于等待时间过长,线程B不想等待了,想处理其他的事情,我们可以让它终端自己或者在别的线程中断它,这就是中断锁。
公平锁,非公平锁。sync是非公平的,哪个线程先来都是随机的。公平锁式先来后到,fairLock。但是往往意味着效率低。
public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable {
ReentrantReadWriteLock并未实现Lock接口,它实现的是ReadWriteLock接口。
读写锁对一个资源的访问,分成了两个锁,一个读锁和一个写锁。
正因为有了读写锁,才使得多个线程之间的读操作不会发生冲突。
在没有读写锁之前,是通过sync实现的。
public class lockTest { private ReentrantReadWriteLock rw1 = new ReentrantReadWriteLock(); public static void main(String[] args) { final lockTest test = new lockTest(); new Thread(){ public void run(){ test.get(Thread.currentThread()); } }.start(); new Thread(){ public void run(){ test.get(Thread.currentThread()); } }.start(); } private synchronized void get(Thread currentThread) { long start = System.currentTimeMillis(); while (System.currentTimeMillis() - start <= 1){ System.out.println(currentThread.getName()+"正在进行读操作"); } System.out.println(currentThread.getName()+"读操作完毕"); } }
而用读锁或者写锁的时候呢,
public class lockTest { private ReentrantReadWriteLock rw1 = new ReentrantReadWriteLock(); public static void main(String[] args) { final lockTest test = new lockTest(); new Thread(){ public void run(){ test.get(Thread.currentThread()); } }.start(); new Thread(){ public void run(){ test.get(Thread.currentThread()); } }.start(); } // private synchronized void get(Thread currentThread) { // long start = System.currentTimeMillis(); // while (System.currentTimeMillis() - start <= 1){ // System.out.println(currentThread.getName()+"正在进行读操作"); // } // System.out.println(currentThread.getName()+"读操作完毕"); // } private void get(Thread currentThread) { try{ //获取一个读锁,再锁上 // rw1.readLock().lock(); rw1.writeLock().lock(); long start = System.currentTimeMillis(); while (System.currentTimeMillis() - start <= 1){ System.out.println(currentThread.getName()+"正在进行读操作"); } System.out.println(currentThread.getName()+"读操作完毕"); }catch (Exception e){ e.printStackTrace(); }finally { // rw1.readLock().unlock(); rw1.writeLock().unlock(); } } }
可以用来提高某些集合的并发性能。当集合比较大,并且读比写频繁时,可以使用该类。
乐观锁和悲观锁。这是数据库层面的锁。
悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次拿数据的时候都会上锁。
乐观锁:每次去拿数据的时候,都认为别人不会上锁,所以不会上锁。