避免死锁的几个常见方法
1.避免一个线程同时获取多个锁
2.避免一个锁同时占有多个资源
3.使用定时锁 lock.tryLock(time) 来代替内置锁(synchronized)
Synchronized底层实现原理
代码块同步是通过monitorenter和monitorexit指令实现,monitorenter指令在编译后
插入到代码块开始的位置,monitorexit指令在代码块结束的位置。任何对象都有一个monitor与之对应,当线程执行到monitorenter处,就会尝试获取到对象所对应monitor所有权。
cas实现原子操作
jvm的cas操作是通过处理器提供的指令实现的,是基于硬件上的操作。一个基于cas的计数器如下
public class Counter { private AtomicInteger atomicI = new AtomicInteger(0); private int i = 0; public static void main(String[] args) { final Counter cas = new Counter(); List<Thread> ts = new ArrayList<Thread>(600); long start = System.currentTimeMillis(); for (int j = 0; j < 100; j++) { Thread t = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 1000; i++) { cas.count(); // 非线程安全相加 cas.safeCount(); // } } }); ts.add(t); } for (Thread t : ts) { t.start(); } // 等待所有线程执行完成 for (Thread t : ts) { try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(cas.i); System.out.println(cas.atomicI.get()); System.out.println(System.currentTimeMillis() - start); } /** * 使用CAS实现线程安全计数器 */ private void safeCount() { for (;;) { int i = atomicI.get(); //读取value值,赋给i,i在线程的工作内存中 //将主内存中的值(current)与工作内存中的值i相比较,如果相等的话,说明工作内存中的i值仍然是value的最新值 // 计数运算对当前i操作没有问题,将value值设为i+1,因为value是violent的,所以写的时候也就写到了主内存 boolean suc = atomicI.compareAndSet(i, ++i); if (suc) { break; } } } /** * 非线程安全计数器 */ private void count() { i++; } }总结 java通过锁机制和cas实现原子操作。
如何安全地停止一个线程,通过while判断thread.isInterrupted标记配合使用
public class Shutdown { public static void main(String[] args) throws Exception { Runner one = new Runner(); Thread countThread = new Thread(one, "CountThread"); countThread.start(); // 睡眠1秒,main线程对CountThread进行中断,使CountThread能够感知中断而结束 TimeUnit.SECONDS.sleep(1); countThread.interrupt(); Runner two = new Runner(); countThread = new Thread(two, "CountThread"); countThread.start(); // 睡眠1秒,main线程对Runner two进行取消,使CountThread能够感知on为false而结束 TimeUnit.SECONDS.sleep(1); two.cancel(); } private static class Runner implements Runnable { private long i; private volatile boolean on = true; @Override public void run() { while (on && !Thread.currentThread().isInterrupted()) { i++; } System.out.println("Count i = " + i); } public void cancel() { on = false; } } }