关于互斥锁:
所谓互斥锁, 指的是一次最多只能有一个线程持有的锁. 在jdk1.5之前, 我们通常使用synchronized机制控制多个线程对共享资源的访问. 而现在, Lock提供了比synchronized机制更广泛的锁定操作, Lock和synchronized机制的主要区别:
synchronized机制提供了对与每个对象相关的隐式监视器锁的访问, 并强制所有锁获取和释放均要出现在一个块结构中, 当获取了多个锁时, 它们必须以相反的顺序释放. synchronized机制对锁的释放是隐式的, 只要线程运行的代码超出了synchronized语句块范围, 锁就会被释放. 而Lock机制必须显式的调用Lock对象的unlock()方法才能释放锁, 这为获取锁和释放锁不出现在同一个块结构中, 以及以更自由的顺序释放锁提供了可能.
关于可重入:
一、2.4.1 内部锁
Java 提供了原子性的内置锁机制: sychronized 块。它包含两个部分:锁对象的引用和这个锁保护的代码块:
synchronized(lock) {
// 访问或修改被锁保护的共享状态
}
内部锁扮演了互斥锁( mutual exclusion lock, 也称作 mutex )的角色,一个线程拥有锁的时候,别的线程阻塞等待。
2.4.2 重进入(Reentrancy )
重入性:指的是同一个线程多次试图获取它所占有的锁,请求会成功。当释放锁的时候,直到重入次数清零,锁才释放完毕。
Public class Widget {
Public synchronized void doSomething(){
…
}
}
Public class LoggingWidget extends Widget {
Public synchronized void doSomething(){
System.out.println(toString()+”:calling doSomething”);
Super.doSomething();
}
}
二、一般来说,在多线程程序中,某个任务在持有某对象的锁后才能运行任务,其他任务只有在该任务释放同一对象锁后才能拥有对象锁,然后执行任务。于是,想到,同一个任务在持有同一个对象的锁后,在不释放锁的情况下,继续调用同一个对象的其他同步(synchronized)方法,该任务是否会再次持有该对象锁呢?
答案是肯定的。同一个任务在调用同一个对象上的其他synchronized方法,可以再次获得该对象锁。
synchronized m1(){ //加入此时对锁a的计数是N m2(); //进入m2的方法体之后锁计数是N+1,离开m2后是N } synchronized m2(){}
同一任务和对象锁的问题:http://www.iteye.com/topic/728485
/*public class ReentrantLock extends Object implements Lock, Serializable */
一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。
ReentrantLock 将由最近成功获得锁,并且还没有释放该锁的线程所拥有。当锁没有被另一个线程所拥有时,调用 lock 的线程将成功获取该锁并返回。如果当前线程已经拥有该锁,此方法将立即返回。可以使用 isHeldByCurrentThread() 和 getHoldCount() 方法来检查此情况是否发生。
此类的构造方法接受一个可选的公平 参数。当设置为 true 时,在多个线程的争用下,这些锁倾向于将访问权授予等待时间最长的线程。否则此锁将无法保证任何特定访问顺序。与采用默认设置(使用不公平锁)相比,使用公平锁的程序在许多线程访问时表现为很低的总体吞吐量(即速度很慢,常常极其慢),但是在获得锁和保证锁分配的均衡性时差异较小。不过要注意的是,公平锁不能保证线程调度的公平性。因此,使用公平锁的众多线程中的一员可能获得多倍的成功机会,这种情况发生在其他活动线程没有被处理并且目前并未持有锁时。还要注意的是,未定时的 tryLock 方法并没有使用公平设置。因为即使其他线程正在等待,只要该锁是可用的,此方法就可以获得成功。
JDK:http://www.xasxt.com/java/api/java/util/concurrent/locks/ReentrantLock.html
/*构造方法摘要 ReentrantLock() 创建一个 ReentrantLock 的实例。 ReentrantLock(boolean fair) 创建一个具有给定公平策略的 ReentrantLock。 */
/**public void lock() 获取锁。 如果该锁没有被另一个线程保持,则获取该锁并立即返回,将锁的保持计数设置为 1。 如果当前线程已经保持该锁,则将保持计数加 1,并且该方法立即返回。 如果该锁被另一个线程保持,则出于线程调度的目的,禁用当前线程,并且在获得锁之前,该线程将一直处于休眠状态,此时锁保持计数被设置为 1。 */
ReentrantLock 的lock机制有2种,忽略中断锁和响应中断锁,这给我们带来了很大的灵活性。比如:如果A、B 2个线程去竞争锁,A线程得到了锁,B线程等待,但是A线程这个时候实在有太多事情要处理,就是 一直不返回,B线程可能就会等不及了,想中断自己,不再等待这个锁了,转而处理其他事情。这个时候ReentrantLock就提供了2种机制,第一,B线程中断自己(或者别的线程中断它),但是ReentrantLock 不去响应,继续让B线程等待,你再怎么中断,我全当耳边风(synchronized原语就是如此);第二,B线程中断自己(或者别的线程中断它),ReentrantLock 处理了这个中断,并且不再等待这个锁的到来,完全放弃。请看例子:
Example1:
package test; public interface IBuffer { public void write(); public void read() throws InterruptedException; }
使用Synchronized:
package test; public class Buffer implements IBuffer { private Object lock; public Buffer() { lock = this; } public void write() { synchronized (lock) { long startTime = System.currentTimeMillis(); System.out.println("开始往这个buff写入数据…"); for (;;)// 模拟要处理很长时间 { if (System.currentTimeMillis() - startTime > Integer.MAX_VALUE) break; } System.out.println("终于写完了"); } } public void read() { synchronized (lock) { System.out.println("从这个buff读数据"); } } }
使用ReentrantLock:
package test; import java.util.concurrent.locks.ReentrantLock; public class BufferInterruptibly implements IBuffer { private ReentrantLock lock = new ReentrantLock(); public void write() { lock.lock(); try { long startTime = System.currentTimeMillis(); System.out.println("开始往这个buff写入数据…"); for (;;)// 模拟要处理很长时间 { if (System.currentTimeMillis() - startTime > Integer.MAX_VALUE) break; } System.out.println("终于写完了"); } finally { lock.unlock(); } } public void read() throws InterruptedException{ lock.lockInterruptibly();// 注意这里,可以响应中断 try { System.out.println("从这个buff读数据"); } finally { lock.unlock(); } } }
测试类(注意那两个线程不是内部类!):
package test; public class Test { //是用ReentrantLock,还是用synchronized public static boolean useSynchronized = false; public static void main(String[] args) { IBuffer buff = null; if(useSynchronized){ buff = new Buffer(); }else{ buff = new BufferInterruptibly(); } final Writer writer = new Writer(buff); final Reader reader = new Reader(buff); writer.start(); reader.start(); new Thread(new Runnable() { public void run() { long start = System.currentTimeMillis(); for (;;) { // 等5秒钟去中断读 if (System.currentTimeMillis() - start > 5000) { System.out.println("不等了,尝试中断"); reader.interrupt(); break; } } } }).start(); } } class Writer extends Thread { private IBuffer buff; public Writer(IBuffer buff) { this.buff = buff; } @Override public void run() { buff.write(); } } class Reader extends Thread { private IBuffer buff; public Reader(IBuffer buff) { this.buff = buff; } @Override public void run() { try { buff.read(); } catch (InterruptedException e) { System.out.println("我不读了"); } System.out.println("读结束"); } }
结果:
使用ReentrantLock时:
开始往这个buff写入数据…
不等了,尝试中断
我不读了
读结束
使用Synchronized时:
开始往这个buff写入数据…
不等了,尝试中断
实例来源:http://blog.csdn.net/quqi99/article/details/5298017
实例2:
http://junlas.iteye.com/blog/846460
实例3:
http://www.blogjava.net/killme2008/archive/2007/09/14/145195.html
重要:
一个证明可中断的例子:http://yanxuxin.iteye.com/blog/566713
关于多线程问题,signalAll,await问题:http://www.iteye.com/problems/72378
ReentrantLock :http://hujin.iteye.com/blog/479689
java的concurrent用法详解:
http://www.open-open.com/bbs/view/1320131360999
ReentrantLock-互斥同步器:
http://www.cnblogs.com/mandela/archive/2011/04/08/2009810.html
一个重要Example:
package tags; import java.util.Calendar; public class TestLock { private ReentrantLock lock = null; public int data = 100; // 用于线程同步访问的共享数据 public TestLock() { lock = new ReentrantLock(); // 创建一个自由竞争的可重入锁 } public ReentrantLock getLock() { return lock; } public void testReentry() { lock.lock(); Calendar now = Calendar.getInstance(); System.out.println(now.getTime() + " " + Thread.currentThread() + " get lock."); } public static void main(String[] args) { TestLock tester = new TestLock(); //1、测试可重入 tester.testReentry(); tester.testReentry(); // 能执行到这里而不阻塞,表示锁可重入 tester.testReentry(); // 再次重入 // 释放重入测试的锁,要按重入的数量解锁,否则其他线程无法获取该锁。 tester.getLock().unlock(); tester.getLock().unlock(); tester.getLock().unlock(); //2、测试互斥 // 启动3个线程测试在锁保护下的共享数据data的访问 new Thread(new workerThread(tester)).start(); new Thread(new workerThread(tester)).start(); new Thread(new workerThread(tester)).start(); } // 线程调用的方法 public void testRun() throws Exception { lock.lock(); Calendar now = Calendar.getInstance(); try { // 获取锁后显示 当前时间 当前调用线程 共享数据的值(并使共享数据 + 1) System.out.println(now.getTime() + " " + Thread.currentThread()+ " accesses the data " + data++); Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } } // 工作线程,调用TestServer.testRun class workerThread implements Runnable { private TestLock tester = null; public workerThread(TestLock testLock) { this.tester = testLock; } public void run() { try { tester.testRun(); } catch (Exception e) { e.printStackTrace(); } } }
Example3:
package tags; import java.util.concurrent.locks.ReentrantLock; public class ReentrantLockSample { public static void main(String[] args) { testSynchronized(); //testReentrantLock(); } public static void testReentrantLock() { final SampleSupport1 support = new SampleSupport1(); Thread first = new Thread(new Runnable() { public void run() { try { support.doSomething(); } catch (InterruptedException e) { e.printStackTrace(); } } }); Thread second = new Thread(new Runnable() { public void run() { try { support.doSomething(); } catch (InterruptedException e) { System.out.println("Second Thread Interrupted without executing counter++,beacuse it waits a long time."); } } }); executeTest(first, second); } public static void testSynchronized() { final SampleSupport2 support2 = new SampleSupport2(); Runnable runnable = new Runnable() { public void run() { support2.doSomething(); } }; Thread third = new Thread(runnable); Thread fourth = new Thread(runnable); executeTest(third, fourth); } /** * Make thread a run faster than thread b, * then thread b will be interruted after about 1s. * @param a * @param b */ public static void executeTest(Thread a, Thread b) { a.start(); try { Thread.sleep(100); b.start(); // The main thread sleep 100ms, and then start the second thread. Thread.sleep(1000); // 1s later, the main thread decided not to allow the second thread wait any longer. b.interrupt(); } catch (InterruptedException e) { e.printStackTrace(); } } } abstract class SampleSupport { protected int counter; /** * A simple countdown,it will stop after about 5s. */ public void startTheCountdown() { long currentTime = System.currentTimeMillis(); for (;;) { long diff = System.currentTimeMillis() - currentTime; if (diff > 5000) { break; } } } } class SampleSupport1 extends SampleSupport { private final ReentrantLock lock = new ReentrantLock(); public void doSomething() throws InterruptedException { lock.lockInterruptibly(); // (1) System.out.println(Thread.currentThread().getName() + " will execute counter++."); startTheCountdown(); try { counter++; } finally { lock.unlock(); } } } class SampleSupport2 extends SampleSupport { public synchronized void doSomething() { System.out.println(Thread.currentThread().getName() + " will execute counter++."); startTheCountdown(); counter++; } }
在这个例子中,辅助类SampleSupport提供一个倒计时的功能startTheCountdown(),这里倒计时5s左右。SampleSupport1,SampleSupport2继承其并分别的具有doSomething()方法,任何进入方法的线程会运行5s左右之后counter++然后离开方法释放锁。SampleSupport1是使用ReentrantLock机制,SampleSupport2是使用synchronized机制。
testSynchronized()和testReentrantLock()都分别开启两个线程执行测试方法executeTest(),这个方法会让一个线程先启动,另一个过100ms左右启动,并且隔1s左右试图中断后者。结果正如之前提到的第二点:interrupt()对于synchronized是没有作用的,它依然会等待5s左右获得锁执行counter++;而ReentrantLock机制可以保证在线程还未获得并且试图获得锁时如果发现线程中断,则抛出异常清除中断标记退出竞争。所以testReentrantLock()中second线程不会继续去竞争锁,执行异常内的打印语句后线程运行结束。
来源:http://yanxuxin.iteye.com/blog/566713
Example4:
三个线程,线程名分别为A、B、C,设计程序使得三个线程循环打印“ABC”10次后终止。如:ABCABCABCABCABCABCABCABCABCABC
package tags; import java.util.concurrent.locks.ReentrantLock; public class ReentrantLockPractice { static ReentrantLock lock = new ReentrantLock(); private static String[] threadArr = {"A","B","C"}; public static void main(String[] args){ ReentrantLockPractice pc = new ReentrantLockPractice(); pc.startDemo(); } void startDemo(){ for(int i = 0;i<10;i++){ for(String name : threadArr){ TestThread t = new TestThread(name); t.start(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } class TestThread extends Thread{ //自定义线程名字 TestThread(String str){ super(str); } public void run(){ try { lock.lockInterruptibly(); System.out.print(Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } finally{ lock.unlock(); } } } }
注意与Example2的区别,一个线材类定义在内部,一个在外部,注意区别。
其他方法:
http://hxraid.iteye.com/blog/607228
相同:ReentrantLock提供了synchronized类似的功能和内存语义。
不同:
1.ReentrantLock功能性方面更全面,比如时间锁等候,可中断锁等候,锁投票等,因此更有扩展性。在多个条件变量和高度竞争锁的地方,用ReentrantLock更合适,ReentrantLock还提供了Condition,对线程的等待和唤醒等操作更加灵活,一个ReentrantLock可以有多个Condition实例,所以更有扩展性。
2.ReentrantLock必须在finally中释放锁,否则后果很严重,编码角度来说使用synchronized更加简单,不容易遗漏或者出错。
3.ReentrantLock 的性能比synchronized会好点。
4.ReentrantLock提供了可轮询的锁请求,他可以尝试的去取得锁,如果取得成功则继续处理,取得不成功,可以等下次运行的时候处理,所以不容易产生死锁,而synchronized则一旦进入锁请求要么成功,要么一直阻塞,所以更容易产生死锁。
1、Lock的某些方法可以决定多长时间内尝试获取锁,如果获取不到就抛异常,这样就可以一定程度上减轻死锁的可能性。
如果锁被另一个线程占据了,synchronized只会一直等待,很容易错序死锁
2、synchronized的话,锁的范围是整个方法或synchronized块部分;而Lock因为是方法调用,可以跨方法,灵活性更大
3、便于测试,单元测试时,可以模拟Lock,确定是否获得了锁,而synchronized就没办法了
ReentrantLock比synchronized 强大在哪儿?
简单说:
1、ReentrantLock可以实现fair lock
public ReentrantLock(boolean fair) {
sync = (fair)? new FairSync() : new NonfairSync();
}
所谓fair lock就是看获得锁的顺序是不是和申请锁的时间的顺序是一致的
2、ReentrantLock支持中断处理
public final void acquireInterruptibly(int arg) throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
就是说那些持有锁的线程一直不释放,正在等待的线程可以放弃等待。
3、ReentrantLock可以和condition结合使用
public boolean hasWaiters(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
}
public int getWaitQueueLength(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
}
内置锁synchronized
显式锁Lock
ReentrantLock代码剖析之ReentrantLock.lock
ReentrantLock中tryLock的使用问题(注意循环)
synchronized是可重入锁
如果一个获取锁的线程调用其它的synchronized修饰的方法,会发生什么?
从设计上讲,当一个线程请求一个由其他线程持有的对象锁时,该线程会阻塞。当线程请求自己持有的对象锁时,如果该线程是重入锁,请求就会成功,否则阻塞。
我们回来看synchronized,synchronized拥有强制原子性的内部锁机制,是一个可重入锁。因此,在一个线程使用synchronized方法时调用该对象另一个synchronized方法,即一个线程得到一个对象锁后再次请求该对象锁,是永远可以拿到锁的。
在Java内部,同一个线程调用自己类中其他synchronized方法/块时不会阻碍该线程的执行,同一个线程对同一个对象锁是可重入的,同一个线程可以获取同一把锁多次,也就是可以多次重入。原因是Java中线程获得对象锁的操作是以线程为单位的,而不是以调用为单位的。
synchronized可重入锁的实现
每个锁关联一个线程持有者和一个计数器。当计数器为0时表示该锁没有被任何线程持有,那么任何线程都都可能获得该锁而调用相应方法。当一个线程请求成功后,JVM会记下持有锁的线程,并将计数器计为1。此时其他线程请求该锁,则必须等待。而该持有锁的线程如果再次请求这个锁,就可以再次拿到这个锁,同时计数器会递增。当线程退出一个synchronized方法/块时,计数器会递减,如果计数器为0则释放该锁。
相关推荐
内容概要:本文详细介绍了基于MATLAB GUI界面和卷积神经网络(CNN)的模糊车牌识别系统。该系统旨在解决现实中车牌因模糊不清导致识别困难的问题。文中阐述了整个流程的关键步骤,包括图像的模糊还原、灰度化、阈值化、边缘检测、孔洞填充、形态学操作、滤波操作、车牌定位、字符分割以及最终的字符识别。通过使用维纳滤波或最小二乘法约束滤波进行模糊还原,再利用CNN的强大特征提取能力完成字符分类。此外,还特别强调了MATLAB GUI界面的设计,使得用户能直观便捷地操作整个系统。 适合人群:对图像处理和深度学习感兴趣的科研人员、高校学生及从事相关领域的工程师。 使用场景及目标:适用于交通管理、智能停车场等领域,用于提升车牌识别的准确性和效率,特别是在面对模糊车牌时的表现。 其他说明:文中提供了部分关键代码片段作为参考,并对实验结果进行了详细的分析,展示了系统在不同环境下的表现情况及其潜在的应用前景。
嵌入式八股文面试题库资料知识宝典-计算机专业试题.zip
嵌入式八股文面试题库资料知识宝典-C and C++ normal interview_3.zip
内容概要:本文深入探讨了一款额定功率为4kW的开关磁阻电机,详细介绍了其性能参数如额定功率、转速、效率、输出转矩和脉动率等。同时,文章还展示了利用RMxprt、Maxwell 2D和3D模型对该电机进行仿真的方法和技术,通过外电路分析进一步研究其电气性能和动态响应特性。最后,文章提供了基于RMxprt模型的MATLAB仿真代码示例,帮助读者理解电机的工作原理及其性能特点。 适合人群:从事电机设计、工业自动化领域的工程师和技术人员,尤其是对开关磁阻电机感兴趣的科研工作者。 使用场景及目标:适用于希望深入了解开关磁阻电机特性和建模技术的研究人员,在新产品开发或现有产品改进时作为参考资料。 其他说明:文中提供的代码示例仅用于演示目的,实际操作时需根据所用软件的具体情况进行适当修改。
少儿编程scratch项目源代码文件案例素材-剑客冲刺.zip
少儿编程scratch项目源代码文件案例素材-几何冲刺 转瞬即逝.zip
内容概要:本文详细介绍了基于PID控制器的四象限直流电机速度驱动控制系统仿真模型及其永磁直流电机(PMDC)转速控制模型。首先阐述了PID控制器的工作原理,即通过对系统误差的比例、积分和微分运算来调整电机的驱动信号,从而实现转速的精确控制。接着讨论了如何利用PID控制器使有刷PMDC电机在四个象限中精确跟踪参考速度,并展示了仿真模型在应对快速负载扰动时的有效性和稳定性。最后,提供了Simulink仿真模型和详细的Word模型说明文档,帮助读者理解和调整PID控制器参数,以达到最佳控制效果。 适合人群:从事电力电子与电机控制领域的研究人员和技术人员,尤其是对四象限直流电机速度驱动控制系统感兴趣的读者。 使用场景及目标:适用于需要深入了解和掌握四象限直流电机速度驱动控制系统设计与实现的研究人员和技术人员。目标是在实际项目中能够运用PID控制器实现电机转速的精确控制,并提高系统的稳定性和抗干扰能力。 其他说明:文中引用了多篇相关领域的权威文献,确保了理论依据的可靠性和实用性。此外,提供的Simulink模型和Word文档有助于读者更好地理解和实践所介绍的内容。
嵌入式八股文面试题库资料知识宝典-2013年海康威视校园招聘嵌入式开发笔试题.zip
少儿编程scratch项目源代码文件案例素材-驾驶通关.zip
小区开放对周边道路通行能力影响的研究.pdf
内容概要:本文探讨了冷链物流车辆路径优化问题,特别是如何通过NSGA-2遗传算法和软硬时间窗策略来实现高效、环保和高客户满意度的路径规划。文中介绍了冷链物流的特点及其重要性,提出了软时间窗概念,允许一定的配送时间弹性,同时考虑碳排放成本,以达到绿色物流的目的。此外,还讨论了如何将客户满意度作为路径优化的重要评价标准之一。最后,通过一段简化的Python代码展示了遗传算法的应用。 适合人群:从事物流管理、冷链物流运营的专业人士,以及对遗传算法和路径优化感兴趣的科研人员和技术开发者。 使用场景及目标:适用于冷链物流企业,旨在优化配送路线,降低运营成本,减少碳排放,提升客户满意度。目标是帮助企业实现绿色、高效的物流配送系统。 其他说明:文中提供的代码仅为示意,实际应用需根据具体情况调整参数设置和模型构建。
少儿编程scratch项目源代码文件案例素材-恐怖矿井.zip
内容概要:本文详细介绍了基于STM32F030的无刷电机控制方案,重点在于高压FOC(磁场定向控制)技术和滑膜无感FOC的应用。该方案实现了过载、过欠压、堵转等多种保护机制,并提供了完整的源码、原理图和PCB设计。文中展示了关键代码片段,如滑膜观测器和电流环处理,以及保护机制的具体实现方法。此外,还提到了方案的移植要点和实际测试效果,确保系统的稳定性和高效性。 适合人群:嵌入式系统开发者、电机控制系统工程师、硬件工程师。 使用场景及目标:适用于需要高性能无刷电机控制的应用场景,如工业自动化设备、无人机、电动工具等。目标是提供一种成熟的、经过验证的无刷电机控制方案,帮助开发者快速实现并优化电机控制性能。 其他说明:提供的资料包括详细的原理图、PCB设计文件、源码及测试视频,方便开发者进行学习和应用。
基于有限体积法Godunov格式的管道泄漏检测模型研究.pdf
嵌入式八股文面试题库资料知识宝典-CC++笔试题-深圳有为(2019.2.28)1.zip
少儿编程scratch项目源代码文件案例素材-几何冲刺 V1.5.zip
Android系统开发_Linux内核配置_USB-HID设备模拟_通过root权限将Android设备转换为全功能USB键盘的项目实现_该项目需要内核支持configFS文件系统
C# WPF - LiveCharts Project
少儿编程scratch项目源代码文件案例素材-恐怖叉子 动画.zip
嵌入式八股文面试题库资料知识宝典-嵌⼊式⼯程师⾯试⾼频问题.zip