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. HDU——2067 小兔的棋盘

    小兔的棋盘 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Subm ...

  2. 武大OJ 612. Catch the sheep

    Description Old Sama is a great and powerful magician in the word. One day, a little girl, Anny, tou ...

  3. 【python】range的用法

    range的用法: >>> range(1,5) #代表从1到5(不包含5)[1, 2, 3, 4]>>> range(1,5,2) #代表从1到5,间隔2(不包含 ...

  4. Linux内核project导论——前言

    想要研究linux内核.使用linux内核,首先要知道linux内核能做到什么,提供了什么.我看过非常多刚開始学习的人一进入公司就開始使用linux内核开发内核模块.使用的不管是通信方式.内存接口还是 ...

  5. 一个unity3d lightmap问题

    上周美术同学在使用unity3d制作lightmap的过程中,发现部分被lightmap影响的模型在移动端上效果与pc端不一致.当时我大概看了下,分析后,得到一个结论是“在移动端上lightmap的h ...

  6. Android 录制屏幕的实现方法

    Android 录制屏幕的实现方法 Chrome   2017-02-15 15:32:01 发布 您的评价:       5.0   收藏     0收藏 长久以来,我一直希望能够直接从Androi ...

  7. Why is processing a sorted array faster than an unsorted array(Stackoverflow)

    What is Branch Prediction? Consider a railroad junction: Image by Mecanismo, via Wikimedia Commons. ...

  8. HVR数据复制软件部署之(一)--HUB端部署

    HVR数据复制软件部署之(一)--HUB端部署 本文环境: OS: RHEL5.9 x86-64bit DB: Oracle 12.1.0.2 x86-64bit HVR:highgohvr-4.7. ...

  9. MongoDB 开机自启动

    MongoDB安装了以后,应当设置开机自启动. 假设启动命令如下: sudo /db/mongodb/265/bin/mongod --config /db/conf/mongodb/mongodb. ...

  10. sql server中数据约束相关的查询

    根据表名查找数据约束 SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = 'CMS_EventLog'; SEL ...