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. 百练4103:踩方格(DFS)

    描述 有一个方格矩阵,矩阵边界在无穷远处.我们做如下假设:a.    每走一步时,只能从当前方格移动一格,走到某个相邻的方格上:b.    走过的格子立即塌陷无法再走第二次:c.    只能向北.东. ...

  2. nyoj 55 懒省事的小明(priority_queue优先队列)

    懒省事的小明 时间限制:3000 ms  |  内存限制:65535 KB 难度:3   描述       小明很想吃果子,正好果园果子熟了.在果园里,小明已经将所有的果子打了下来,而且按果子的不同种 ...

  3. RabbitMQ-rabbitmqctl和插件使用(四)

    rabbitmqctl 说明 进入mq的bin目录 cd /usr/local/Cellar/rabbitmq/3.7.8/sbin ./rabbitmqctl [-n node] [-t timeo ...

  4. JWT & HMAC-SHA256

    JWT JSON Web Tokens https://jwt.io/ https://en.wikipedia.org/wiki/JSON_Web_Token#Structure HMACSHA25 ...

  5. [luoguP1220] 关路灯(DP)

    传送门 如果去关某一个灯,那么途中经过的灯都能关闭,那么就是连续一段区间,区间DP. f[i][j][0] 表示关完 i, j 这个区间且在 i 这个位置 f[i][j][1] 表示关完 i, j 这 ...

  6. hdu 2545 并查集 树上战争

    #include<stdio.h> #include<string.h> #define N 110000 struct node {     int father,count ...

  7. 【BZOJ4199&UOJ131】品酒大会(后缀数组,并查集)

    题意: 两杯“r相似” (r>1)的酒同时也是“1 相似”.“2 相似”.…….“(r−1) 相似”的. n<=300000 abs(a[i])<=10^9 思路:对于i,j两个后缀 ...

  8. loginitem

    + (BOOL) willStartAtLogin:(NSURL *)itemURL { Boolean foundIt=false; LSSharedFileListRef loginItems = ...

  9. 移动端,input输入获得焦点被键盘遮住简单解决方案

    (function (window,document) { document.querySelector('input[type="text"]').addEventListene ...

  10. nodejs 运行

    运行 Node.js 程序的基本方法就是执行 node script.js,其中 script.js①是脚本的文件名. 除了直接运行脚本文件外,node --help 显示的使用方法中说明了另一种输出 ...