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. Linux上安装Hadoop集群(CentOS7+hadoop-2.8.0)--------hadoop环境的搭建

    Linux上安装Hadoop集群(CentOS7+hadoop-2.8.0)------https://blog.csdn.net/pucao_cug/article/details/71698903 ...

  2. HUST 1214 Cubic-free numbers II

    Cubic-free numbers II Time Limit: 10000ms Memory Limit: 131072KB This problem will be judged on HUST ...

  3. POJ 2217 Secretary

    Secretary Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged on PKU. Original ID:  ...

  4. Android三角标签View:TriangleLabelView

     Android三角标签View:TriangleLabelView 在一些商城.产品推销类APP中,如淘宝.京东.电影门票销售.商品降价促销这类的APP,常常会在其APP中看到,某些商品的左上角 ...

  5. [luoguP1316] 丢瓶盖(二分答案)

    传送门 二分答案再判断即可 ——代码 #include <cstdio> #include <iostream> #include <algorithm> #def ...

  6. noip模拟赛 动态规划

    题目描述LYK在学习dp,有一天它看到了一道关于dp的题目.这个题目是这个样子的:一开始有n个数,一段区间的价值为这段区间相同的数的对数.我们想把这n个数切成恰好k段区间.之后这n个数的价值为这k段区 ...

  7. vim下多行注释与解注释

    1.多行注释 (1)按esc进入命令行模式 (2)按下Ctrl+v,进入区块模式,并使用上下键选择需要注释的多行 (3)按下“I”(大写)键,进入插入模式 (4)输入注释符(“//”或“#”等) (5 ...

  8. O - Treats for the Cows 区间DP

    FJ has purchased N (1 <= N <= 2000) yummy treats for the cows who get money for giving vast am ...

  9. NOIP2015 提高组合集

    NOIP 2015 提高组 合集 D1 T1 神奇的幻方 题目让你干啥你就干啥,让你咋走你就咋走就完事儿了 #include <iostream> #include <cstdio& ...

  10. FreeMarker与Spring MVC 4结合错误:Caused by: java.lang.NoClassDefFoundError: org/springframework/ui/freemarker/FreeMarkerConfiguration

    添加spring-context-support的依赖到POM: <!-- spring-context-support --> <!-- https://mvnrepository ...