ReentrantLock、synchronized、volatile 向右看齐 2022-09-24 01:25 168阅读 0赞 ### synchronized ### 把代码块声明为 synchronized,有两个重要后果,通常是指该代码具有 原子性和 可见性。原子性意味着一个线程一次只能执行由一把锁保护的代码,从而防止多个线程在更新共享状态时相互冲突。原子操作表示不可被中断的一个或一系列操作。 java 中的每一个对象都可以作为锁。具体表现为一下形式: 1、对于普通同步方法,锁是当前实例对象。 2、对于静态同步方法,锁是当前类的class对象。 3、对于同步方法块,所示synchronized括号里配置的对象。 当一个线程访问同步代码块时,他必须首先得到锁,退出或抛出异常时必须释放锁。 ### Lock 和synchronized ### lock 必须在 finally 块中释放。否则,如果受保护的代码将抛出异常,锁就有可能永远得不到释放! public class T{ private int count = 10; public synchronized void m() { count--; System.out.println(Thread.currentThread().getName() + " count = " + count); } public static void main(String[] args) { T t = new T(); for(int i=0; i<5; i++) { new Thread(t::m, "THREAD" + i).start(); } } } 同步与非同步方法是可以同时调用的,两个同步方法也是可以同时调用的,但是后一个必须等待前一个执行完成才能拿到第二把锁 public class T { public synchronized void m1() { System.out.println(Thread.currentThread().getName() + " m1 start..."); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " m1 end"); } public void m2() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " m2 "); } public static void main(String[] args) { T t = new T(); new Thread(t::m1, "t1").start(); new Thread(t::m2, "t2").start(); } } synchronized获得的锁是可重入的,也就是说,一个同步方法可以调用另外一个同步方法,因为一个线程已经获取对象锁,再次申请的时候还是可以获取到该对象锁 ### ReentrantLock ### 多线程都在争用同一个锁时,使用 ReentrantLock 的总体开支通常要比 synchronized 少得多。 用 ReentrantLock 保护代码块时,一定要使用finally块关闭锁。 public class ReentrantLock2 { Lock lock = new ReentrantLock(); private void m1() { try { lock.lock(); //相当于synchronized(this) for (int i = 0; i < 10; i++) { TimeUnit.SECONDS.sleep(1); System.out.println(i); } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } void m2() { lock.lock(); System.out.println("m2 ..."); lock.unlock(); } public static void main(String[] args) { ReentrantLock2 rl = new ReentrantLock2(); new Thread(rl::m1).start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(rl::m2).start(); } } 以上m1()执行完毕后才会执行m2()。m1()必须手动释放锁,否则m2()永远不会执行。ReentrantLock也可以指定为公平锁,线程调度器计算哪个线程等待的时间比较长,会让它先执行,所以不是绝对公平: public class ReenLock { static Lock lock = new ReentrantLock(true); private void m3() { for (int i = 0; i < 100; i++) { lock.lock(); System.out.println(Thread.currentThread().getName() + " 获得锁"); lock.unlock(); } } public static void main(String[] args) { ReenLock l = new ReenLock(); new Thread(l::m3).start(); new Thread(l::m3).start(); } } ### volatile ### java允许多线程访问共享变量,为了确保共享变量能被准确和一致的更新,线程应该通过互斥单独获得这个变量。如果一个变量被声明为volatile,Java线程内存模型确保所有线程看到这个变量的值是一致的。但它只是保证了可见性,不保证原子性,所以会结合锁一起使用。 jdk1.8后synchronized已经优化,但是还是比volatile重。synchronized是一种悲观锁,一个线程访问某个资源时,它会悲观的认为其他线程也会来访问该资源,java有个乐观锁CAS(Compare And Swap),其设计思想是乐观地认为不会产生并发,所以不上锁,在取数据的时候,判断一下在此期间是否有人修改,如果没有修改,则直接使用。 public class Test { volatile boolean running = true; private void m() { System.out.println(Thread.currentThread().getName() + " m start.."); while (running) { } System.out.println(Thread.currentThread().getName() + " m end.."); } public static void main(String[] args) { Test t = new Test(); new Thread(() -> t.m(), "t1").start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } t.running = false; } } class LoanTask{ static String LOAN_STATUS = "LOAN_STATUS"; } class BorrowTask{ public Object getLock() { return LoanTask.LOAN_STATUS; } Object lock = getLock(); synchronized (lock) { lock.notifyAll();//必须先跟synchronized配合使用 } } 参考示例程序:[lock与unlock][lock_unlock] [java内存模型][java] 以下仅是做记录 ConcurrentUtil.register(user); public void offer(T model) { if (!queue.contains(model)) { queue.offer(model); try { System.out.println("------------11111111--------"); LOCK.lock(); task.execute(); System.out.println("------------33333333--------"); }finally{ LOCK.unlock(); System.out.println("-----44444444444-------"); } } } 再研究下task.execute()这个方法。 [lock_unlock]: http://blog.csdn.net/o9109003234/article/details/12159661 [java]: http://www.cnblogs.com/nexiyi/p/java_memory_model_and_thread.html
还没有评论,来说两句吧...