Java多线程——线程八锁案例分析

摘要:本文主要学习了多线程并发中的一些案例。

部分内容来自以下博客:

https://blog.csdn.net/dyt443733328/article/details/80019352

多线程的八个案例

通过分析代码,推测打印结果,并运行代码进行验证。

1)两个线程调用同一个对象的两个同步方法

代码如下:

 public class Demo {
public static void main(String[] args) {
Number number = new Number(); new Thread(new Runnable() {
@Override
public void run() {
number.getOne();
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
number.getTwo();
}
}).start();
}
} class Number {
public synchronized void getOne() {
System.out.println("one");
} public synchronized void getTwo() {
System.out.println("two");
}
}

运行结果如下:

 one
two

结果分析:

被synchronized修饰的方法,锁的对象是方法的调用者。因为两个方法的调用者是同一个,所以两个方法用的是同一个锁,先调用方法的先执行。

2)新增Thread.sleep()给某个方法

代码如下:

 public class Demo {
public static void main(String[] args) {
Number number = new Number(); new Thread(new Runnable() {
@Override
public void run() {
number.getOne();
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
number.getTwo();
}
}).start();
}
} class Number {
public synchronized void getOne() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("one");
} public synchronized void getTwo() {
System.out.println("two");
}
}

运行结果如下:

 // 等待一秒。
one
two

结果说明:

被synchronized修饰的方法,锁的对象是方法的调用者。因为两个方法的调用者是同一个,所以两个方法用的是同一个锁,先调用方法的先执行,第二个方法只有在第一个方法执行完释放锁之后才能执行。

3)新增一个线程调用新增的一个普通方法

代码如下:

 public class Demo {
public static void main(String[] args) {
Number number = new Number(); new Thread(new Runnable() {
@Override
public void run() {
number.getOne();
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
number.getTwo();
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
number.getThree();
}
}).start();
}
} class Number {
public synchronized void getOne() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("one");
} public synchronized void getTwo() {
System.out.println("two");
} public void getThree() {
System.out.println("three");
}
}

运行结果如下:

 three
// 等待一秒。
one
two

结果说明:

新增的方法没有被synchronized修饰,不是同步方法,不受锁的影响,所以不需要等待。其他线程共用了一把锁,所以还需要等待。

4)两个线程调用两个对象的同步方法,其中一个方法有Thread.sleep()

代码如下:

 public class Demo {
public static void main(String[] args) {
Number numberOne = new Number();
Number numberTwo = new Number(); new Thread(new Runnable() {
@Override
public void run() {
numberOne.getOne();
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
numberTwo.getTwo();
}
}).start();
}
} class Number {
public synchronized void getOne() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("one");
} public synchronized void getTwo() {
System.out.println("two");
}
}

运行结果如下:

 two
// 等待一秒。
one

结果说明:

被synchronized修饰的方法,锁的对象是方法的调用者。因为用了两个对象调用各自的方法,所以两个方法的调用者不是同一个,所以两个方法用的不是同一个锁,后调用的方法不需要等待先调用的方法。

5)将有Thread.sleep()的方法设置为static方法,并且让两个线程用同一个对象调用两个方法

代码如下:

 public class Demo {
public static void main(String[] args) {
Number number = new Number(); new Thread(new Runnable() {
@Override
public void run() {
number.getOne();
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
number.getTwo();
}
}).start();
}
} class Number {
public static synchronized void getOne() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("one");
} public synchronized void getTwo() {
System.out.println("two");
}
}

运行结果如下:

 two
// 等待一秒。
one

结果说明:

被synchronized和static修饰的方法,锁的对象是类的class对象。仅仅被synchronized修饰的方法,锁的对象是方法的调用者。因为两个方法锁的对象不是同一个,所以两个方法用的不是同一个锁,后调用的方法不需要等待先调用的方法。

6)将两个方法均设置为static方法,并且让两个线程用同一个对象调用两个方法

代码如下:

 public class Demo {
public static void main(String[] args) {
Number number = new Number(); new Thread(new Runnable() {
@Override
public void run() {
number.getOne();
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
number.getTwo();
}
}).start();
}
} class Number {
public static synchronized void getOne() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("one");
} public static synchronized void getTwo() {
System.out.println("two");
}
}

运行结果如下:

 // 等待一秒。
one
two

结果说明:

被synchronized和static修饰的方法,锁的对象是类的class对象。因为两个同步方法都被static修饰了,所以两个方法用的是同一个锁,后调用的方法需要等待先调用的方法。

7)将两个方法中有Thread.sleep()的方法设置为static方法,另一个方法去掉static修饰,让两个线程用两个对象调用两个方法

代码如下:

 public class Demo {
public static void main(String[] args) {
Number numberOne = new Number();
Number numberTwo = new Number(); new Thread(new Runnable() {
@Override
public void run() {
numberOne.getOne();
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
numberTwo.getTwo();
}
}).start();
}
} class Number {
public static synchronized void getOne() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("one");
} public synchronized void getTwo() {
System.out.println("two");
}
}

运行结果如下:

 two
// 等待一秒。
one

结果说明:

被synchronized和static修饰的方法,锁的对象是类的class对象。仅仅被synchronized修饰的方法,锁的对象是方法的调用者。即便是用同一个对象调用两个方法,锁的对象也不是同一个,所以两个方法用的不是同一个锁,后调用的方法不需要等待先调用的方法。

8)将两个方法均设置为static方法,并且让两个线程用同一个对象调用两个方法

代码如下:

 public class Demo {
public static void main(String[] args) {
Number numberOne = new Number();
Number numberTwo = new Number(); new Thread(new Runnable() {
@Override
public void run() {
numberOne.getOne();
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
numberTwo.getTwo();
}
}).start();
}
} class Number {
public static synchronized void getOne() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("one");
} public static synchronized void getTwo() {
System.out.println("two");
}
}

运行结果如下:

 // 等待一秒。
one
two

结果说明:

被synchronized和static修饰的方法,锁的对象是类的class对象。因为两个同步方法都被static修饰了,即便用了两个不同的对象调用方法,两个方法用的还是同一个锁,后调用的方法需要等待先调用的方法。

总结

一个类里面如果有多个synchronized方法,在使用同一个对象调用的前提下,某一个时刻内,只要一个线程去调用其中的一个synchronized方法了,其他的线程都只能等待,换句话说,某一时刻内,只能有唯一一个线程去访问这些synchronized方法。

锁的是当前对象this,被锁定后,其他线程都不能进入到当前对象的其他的synchronized方法。

加个普通方法后发现和同步锁无关。

换成静态同步方法后,情况又变化。

所有的非静态同步方法用的都是同一把锁:实例对象本身。

也就是说如果一个对象的非静态同步方法获取锁后,该对象的其他非静态同步方法必须等待获取锁的方法释放锁后才能获取锁,可是其他对象的非静态同步方法因为跟该对象的非静态同步方法用的是不同的锁,所以毋须等待该对象的非静态同步方法释放锁就可以获取他们自己的锁。

所有的静态同步方法用的也是同一把锁:类对象本身。

这两把锁是两个不同的对象,所以静态同步方法与非静态同步方法之间不会有竞争条件。但是一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁,而不管是同一个对象的静态同步方法,还是其他对象的静态同步方法,只要它们属于同一个类的对象,那么就需要等待当前正在执行的静态同步方法释放锁。

Java多线程——线程八锁案例分析的更多相关文章

  1. java多线程 -- 线程八锁

    一个对象里面如果有多个synchronized方法,某一个时刻内,只要一个线程去调用其中的一个synchronized方法了,其它的线程都只能等待,换句话说,某一个时刻内,只能有唯一一个线程去访问这些 ...

  2. java多线程----线程池源码分析

    http://www.cnblogs.com/skywang12345/p/3509954.html 线程池示例 在分析线程池之前,先看一个简单的线程池示例. 1 import java.util.c ...

  3. java多线程——线程池源码分析(一)

    本文首发于cdream的个人博客,点击获得更好的阅读体验! 欢迎转载,转载请注明出处. 通常应用多线程技术时,我们并不会直接创建一个线程,因为系统启动一个新线程的成本是比较高的,涉及与操作系统的交互, ...

  4. Java多线程-线程的锁总结

    一.多线程-同步函数的锁是this /*同步函数用的是哪一个锁呢?函数需要被对象调用.那么函数都有一个所属对象引用.就是this.所以同步函数使用的锁是this. 通过该程序进行验证. 使用两个线程来 ...

  5. Java多线程系列--“JUC锁”03之 公平锁(一)

    概要 本章对“公平锁”的获取锁机制进行介绍(本文的公平锁指的是互斥锁的公平锁),内容包括:基本概念ReentrantLock数据结构参考代码获取公平锁(基于JDK1.7.0_40)一. tryAcqu ...

  6. Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例

    概要 本章介绍JUC包中的CyclicBarrier锁.内容包括:CyclicBarrier简介CyclicBarrier数据结构CyclicBarrier源码分析(基于JDK1.7.0_40)Cyc ...

  7. Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock

    本章对ReentrantLock包进行基本介绍,这一章主要对ReentrantLock进行概括性的介绍,内容包括:ReentrantLock介绍ReentrantLock函数列表ReentrantLo ...

  8. Java多线程系列--“JUC锁”01之 框架

    本章,我们介绍锁的架构:后面的章节将会对它们逐个进行分析介绍.目录如下:01. Java多线程系列--“JUC锁”01之 框架02. Java多线程系列--“JUC锁”02之 互斥锁Reentrant ...

  9. Java多线程系列--“JUC锁”09之 CountDownLatch原理和示例

    概要 前面对"独占锁"和"共享锁"有了个大致的了解:本章,我们对CountDownLatch进行学习.和ReadWriteLock.ReadLock一样,Cou ...

随机推荐

  1. mongodb replica set 添加/删除节点方法--http://www.ii123.com/jc/bc/bczh/258948.html

    replica set多服务器主从,添加,删除节点,肯定会经常遇到的.下面详细说明一下,添加,删除节点的2种方法. 一,利用rs.reconfig,来添加,删除节点 1,添加节点  代码如下   re ...

  2. [luoguP1373] 小a和uim之大逃离(DP)

    传送门 题解 代码 #include <cstdio> #include <iostream> #define N 802 #define mod 1000000007 int ...

  3. [luoguP2031] 脑力达人之分割字串(DP)

    传送门 想了个4次方算法,没想到也A了,数据真是水. 其实两个字符串匹配那部分可以用kmp优化 ——代码 #include <cstdio> #include <cstring> ...

  4. Codeforces Round #239(Div. 2) 做后扯淡玩

    今天补了下 cf 239div2 顿时信心再度受挫 老子几乎已经木有时间了啊 坐着等死的命.哎!!! 到现在还只能做大众题,打铁都不行. 每次D题都是有思路敲错,尼玛不带这么坑爹的. 哎!不写了,写这 ...

  5. 兼容IE8 addEventListener、removeEventListener 函数

    //兼容bind函数 if(!Function.prototype.bind){ Function.prototype.bind = function(){ if(typeof this !== 'f ...

  6. Docker: Docker容器之间互相通信

    最简单的方法,关闭防火墙(只建议用于开发环境) systemctl stop firewalld

  7. Unity3D 怎样在安卓手机上播放视频

    曾经仅仅会在电脑上通过Unity3D播放视频,研究了下发现通过Unity3D在手机上播放视频也很easy.现介绍例如以下. void OnGUI()     {         if (GUI.But ...

  8. 【转】Linux 查看CPU信息、机器型号等硬件信息

    测试机器的硬件信息: 查看CPU信息(型号) # cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c       8  Intel(R) Xeo ...

  9. HDOJ 题目5289 Assignment(RMQ,技巧)

    Assignment Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total ...

  10. 搜狗输入法APP的2个剪切板内容获取入口

    搜狗输入法APP的2个剪切板内容获取入口