本人很少原创技术文章(其他文章页很少),一般都是看别人文章写得就转发一下,但是关于多线程这块我一直都没有找到能说中要害又通俗易懂的文章,本人不是什么大牛,但在java线程锁这一块觉得自己理解的还算正确吧,本着知识共享的精神,今天我就试着把这一块说说,用的都是最通俗的语言,最简单的代码(命名没有做到见文识意,应该批评),希望能帮助困惑中的人解脱出来,如果我理解错了,那么也请大牛们帮我解脱出来,无论如何,要么我受益,要么大家受益。
首先我说一下一部分人的错误理解,网上讲多线程的文章很多,但多数文章看完之后会留下这么一个印象:一个synchronized 关键字会锁住一段代码,被一个synchronized关键字控制的代码块同时只允许一个线程进入;
其实在逻辑上这句话是对的,但他把重点放在了代码块上,这就不对了,这样容易让人进入一个误区,那就是一个synchronized关键字控制区内同时只允许进入一个线程的。哪里错了呢?错就错在一个线程进入一个synchronized区后锁住的不只是那一个synchronized之后的代码块,其他synchronized之后的代码也可能已经被锁住了,因为线程锁的重点不在synchronized关键字和其后的{}的范围,而是synchronized(obj)括号里面的参数obj,这个参数才是应该关注的焦点。
我们可以把synchronized看成一个门,synchronized(obj)里面的obj就是钥匙,线程就是要进门的人,人进门前需要先拿钥匙开门,然后带着钥匙进去,进去后锁门不让别人进,出来后再锁上门,然后把钥匙放下,之后另一个人才能再拿上钥匙进出。多个synchronized(obj)就是多扇门,如果它们需要的是同一把钥匙,那么一旦一个人拿着钥匙进入其中一个门,就会导致其他人无法拿到钥匙,也就无法打开所有需要这把钥匙的门,而不只是刚才进入的那个门,拿着钥匙的人可以在多个门里来回进出,其他人就只能在外面等着,千万不要认为拿着钥匙的人进入了一个门就只锁住了那一个门,总结一句话:只要他们用的锁一样,不管代码块在什么位置,都会互相影响。如果这个比方还不够清楚下面我们直接用代码测试吧。
先创建一个测试类,有两个加锁的静态方法:
public class Test1 {
/** 注意这样的静态方法默认是以Test1.class作为钥匙的 相当于synchronized(Test1.class)**/
public synchronized static void staticMethod1(){
//如果我在这里睡觉,那么Test1的staticMethod2别想睡觉,当然如果他先拿到钥匙的话就是他说了算了
System.out.println("Test1.staticMethod1 要睡觉了");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Test1.staticMethod1 睡醒了。。。");
}
/** 注意这样的静态方法默认是以Test1.class作为钥匙的 相当于synchronized(Test1.class)**/
public synchronized static void staticMethod2(){
//如果我在这里睡觉,那么Test1的staticMethod1别想睡觉,当然如果他先拿到钥匙的话就是他说了算了
System.out.println("Test1.staticMethod2 要睡觉了");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Test1.staticMethod2 睡醒了。。。");
}
}
下面再写两个线程类,分别调用上面类的两个方法:
public class MyThread1 extends Thread{
public void run(){
Test1.staticMethod1();
}
}
public class MyThread2 extends Thread{
public void run(){
Test1.staticMethod2();
}
}
好了测试一下吧,下面是测试代码,看官也可以先预测一下结果
public class ThreadTester {
public static void main(String[] args) {
//这里线程启动顺序无所谓,只要一个线程启动了另一线程就必须等待,这是要关注的
new MyThread1().start();
new MyThread2().start();
}
}
通过运行结果大家可以得出一个结论,那就是调用任意一个synchronized(Test1.class)的方法,会锁住所有带synchronized(Test1.class)的方法,因为他们需要的钥匙Test1.class被拿走了。
上面测试了synchronized方法,下面我们再测试一下synchronized(Test1.class)代码块,现在我们新建一个类:
public class Test2 {
public static void staticMethod1(){
synchronized(Test1.class){ //这里的钥匙是Test1.class
//如果我在这里睡觉,那么Test1的方法staticMethod1和staticMethod2都别想睡觉,当然如果他们先拿到钥匙的话就是你们说了算了
System.out.println("Test2.staticMethod1 要睡觉了");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Test2.staticMethod1 睡醒了");
}
}
}
这里,在Test1的外面有一个类Test2竟然有一个方法里面有一段代码用Test1.class作为钥匙,可怕的事情总是这样发生,一定要明白如果这里有什么阻塞的话其他线程调用Test1方法的线程也会被阻塞的
另外再补充一点
public class Test3 {
/** 注意这样的静态方法默认是以this作为钥匙的 相当于synchronized(this)**/
public synchronized void method1(){
}
}
这样的对象方法只有多个线程同时操作同一个对象时才会相互排斥,注意是“同一个对象”,多发生于单例模式;把一个对象传给两个线程做参数的情况也会形成锁竞争,但这种写法比较少见,例如下面情况:
public class MyThread4 extends Thread{
private Test3 t3;
public MyThread4(Test3 t3){
this.t3 = t3;
}
public void run(){
this.t3.method1();
}
}
可以使用同一个Test3 实例构造多个多个MyThread4 线程并依次启动,就可以测出锁竞争
本人才疏学浅,一点心得与大家分享,如有错误,欢迎指教,如果觉得不错,也欢迎转载
分享到:
相关推荐
在编程领域,多线程是实现并发执行任务的重要方式,特别是在多核处理器系统中,它能有效利用...对于初学者来说,分析并实践“多线程互斥锁和条件变量demo”是一个很好的起点,它可以帮助你更好地理解和运用这些工具。
#### 一、线程启动与执行状态的理解误区 **误区解释:** 在Java多线程编程中,一个常见的误区是关于如何正确启动线程以及理解线程的状态。根据提供的代码片段,可以看到有一个`ReturnThreadInfo`类继承自`Thread`...
Java多线程与锁是Java并发编程中的核心概念,它们...综上所述,Java多线程和锁是解决并发问题的关键,它们涉及线程创建、管理、同步和通信等多个方面。通过深入学习和实践,开发者能够构建出更加稳定、高效的并发程序。
读写锁分为读锁和写锁,读锁可由多个线程同时持有,而写锁是独占的,一旦有线程持有了写锁,其他所有线程都无法再获取读锁或写锁。 读写锁的工作原理如下: 1. 当没有线程持有锁时,任何线程都可以获得写锁。 2. 当...
在IT领域,多线程和分布式锁是两个关键的概念,特别是在构建高性能、高并发的系统时。本资源包提供了一套全面的多线程入门学习资料,帮助开发者深入理解这两个主题。 多线程是现代计算机编程中的基础概念,尤其是在...
Java 中的多线程编程需要充分考虑线程安全和锁机制的问题,否则可能会导致程序的执行不稳定和崩溃。Lock 机制是 Java 中的一种重要的线程同步机制,它可以用来实现线程安全和提高程序的执行效率。
在VC++编程环境中,线程同步是一个至关重要的概念,特别...通过合理使用线程锁,我们可以编写出高效且安全的多线程程序。在提供的源码文件中,我们可以深入学习线程锁的实现细节,以及如何在实际项目中有效地运用它们。
设计多线程锁操作系统实现原理、有哪些多线程锁,如何使用这些锁
理解并熟练运用这些概念和技术,可以帮助你在LabWindows/CVI环境中编写出高效且稳定的多线程应用程序,避免因数据不一致或竞态条件而导致的问题。在实践中,要注意合理分配资源,避免死锁,以及对线程性能的优化,...
c++ 使用多线程时要涉及到线程锁的使用, 本例简单易用……
对于一个高性能服务器在处理多数读取,少量写入的场景时,如果还是使用常规的互斥锁方式,显然就不明智了,这种读多写少的场景最适合使用读写锁方式,读取时不加锁,多线程并发读取,效率是最高的,要写入数据时堵塞...
线程锁,又称为同步机制,是为了在多线程环境下保证数据的一致性和完整性而引入的,避免了多个线程同时访问共享资源可能导致的数据不一致问题。下面我们将深入探讨线程和线程锁的概念以及它们在实际应用中的使用。 ...
以上只是Java多线程、锁和内存模型的一部分核心概念,深入理解这些知识点对于编写高效、可靠的并发程序至关重要。在面试中,面试官通常会通过这些问题来评估候选人的并发编程能力。因此,对这些概念的深入理解和实践...
在Java编程语言中,多线程是并发执行多个任务的关键技术。这允许程序在等待某个操作完成时继续处理其他任务,...通过学习这个示例,开发者能够更好地理解和运用Java的并发编程技术,提高多线程应用程序的设计和性能。
在IT领域,多线程是程序设计中的一个重要概念,尤其在现代计算机系统中,它能够充分利用多核处理器的计算能力,提高程序的执行效率。...理解并掌握多线程编程,能帮助开发者编写出更高效、稳定的软件系统。
在C#编程中,多线程技术常用于...总结来说,理解和掌握这些知识点对于在C#中高效且安全地实现多线程读写SQLite数据库至关重要。通过合理利用多线程并正确实施同步策略,可以提高应用程序的并发性能,同时避免数据错误。
线程锁则是确保多线程环境下的数据一致性、避免竞态条件和死锁的重要工具。本示例通过一个简单的银行账户取款问题来阐述多线程和线程锁的概念。 首先,我们有一个`Account`类,它代表银行账户,包含账户ID和余额。...
iOS多线程编程之Grand Central Dispatch(GCD)使用,卖票的例子来讲NSThread的线程同步,使用了两种锁,一种NSCondition ,一种是:NSLock,还有加了一个 线程3 去唤醒其他两个线程锁中的wait,里面的注释很已经写的...
总的来说,理解和掌握多线程中的互斥锁是非常重要的,它有助于我们在并发环境中保证程序的正确性和稳定性。通过合理的线程同步,我们可以有效地避免数据竞争,从而构建更加健壮的多线程应用程序。
本主题将深入探讨多线程的使用以及线程锁的两种主要实现方式: synchronized关键字和ReentrantLock。 一、多线程基础 1. 线程创建: - 继承Thread类:创建一个新的类,该类继承自Thread类,并重写run()方法。然后...