多线程开发离不开锁机制,现在的Java语言中,提供了2种锁,一种是语言特性提供的内置锁,还有一种是 java.util.concurrent.locks 包中的锁,这篇文章简单整理一下内置锁的知识点。

内置锁在Java语言中的表现:

多线程的锁,其实本质上就是给一块内存空间的访问添加访问权限,因为Java中是没有办法直接对某一块内存进行操作的,又因为Java是面向对象的语言,一切皆对象,所以具体的表现就是某一个对象承担锁的功能,每一个对象都可以是一个锁。内置锁,使用方式就是使用 synchronized 关键字,synchronized 方法或者 synchronized 代码块。

每一种 synchronized 写法的锁是哪个对象:

1、指定当前对象加锁:

  1. private synchronized void function() {
  2. //TODO execute something
  3. }

2、指定当前类的Class对象加锁:

  1. private static synchronized void function() {
  2. //TODO execute something
  3. }

注意此处的 static 关键字。

3、指定任意对象加锁:

  1. private void function() {
  2. synchronized (object) {
  3. //TODO execute something
  4. }
  5. }

此时,这段同步代码块的锁加在object对象上面。该对象可以是当前对象(object ==
this),也可以是当前类的Class对象(object == MyClass.class)。

简单验证一下:

现有如下的类:

  1. public class SynchronizedTest {
  2. private Object lock = new Object();
  3.  
  4. public void synchronizedBlockOnObject(long executeTime) {
  5. synchronized (lock) {
  6. System.out.println(Thread.currentThread().getName() + " -> start synchronizedBlockOnObject");
  7. doSomething(executeTime);
  8. System.out.println(Thread.currentThread().getName() + " -> end synchronizedBlockOnObject");
  9. }
  10. }
  11.  
  12. public void synchronizedBlockOnThis(long executeTime) {
  13. synchronized (this) {
  14. System.out.println(Thread.currentThread().getName() + " -> start synchronizedBlockOnThis");
  15. doSomething(executeTime);
  16. System.out.println(Thread.currentThread().getName() + " -> end synchronizedBlockOnThis");
  17. }
  18. }
  19.  
  20. public void synchronizedBlockOnClass(long executeTime) {
  21. synchronized (SynchronizedTest.class) {
  22. System.out.println(Thread.currentThread().getName() + " -> start synchronizedBlockOnClass");
  23. doSomething(executeTime);
  24. System.out.println(Thread.currentThread().getName() + " -> end synchronizedBlockOnClass");
  25. }
  26. }
  27.  
  28. public synchronized void synchronizedMethodOnThis(long executeTime) {
  29. System.out.println(Thread.currentThread().getName() + " -> start synchronizedMethodOnThis");
  30. doSomething(executeTime);
  31. System.out.println(Thread.currentThread().getName() + " -> end synchronizedMethodOnThis");
  32. }
  33.  
  34. public static synchronized void synchronizedMethodOnClass(long executeTime) {
  35. System.out.println(Thread.currentThread().getName() + " -> start synchronizedMethodOnClass");
  36. doSomething(executeTime);
  37. System.out.println(Thread.currentThread().getName() + " -> end synchronizedMethodOnClass");
  38. }
  39.  
  40. private static void doSomething(long executeTime) {
  41. try {
  42. Thread.sleep(executeTime);
  43. } catch (InterruptedException e) {
  44. e.printStackTrace();
  45. }
  46. }
  47. }

1、static synchronized 方法 和 synchronized (MyClass.class) {} 同步代码块的锁都加在
MyClass.class 对象上面:

  1. public static void main(String[] args) {
  2. SynchronizedTest synchronizedTest = new SynchronizedTest();
  3.  
  4. new Thread(new Runnable() {
  5. @Override
  6. public void run() {
  7. SynchronizedTest.synchronizedMethodOnClass(3000);
  8. }
  9. }, "Thread static synchronized method").start();
  10. new Thread(new Runnable() {
  11. @Override
  12. public void run() {
  13. synchronizedTest.synchronizedBlockOnClass(2000);
  14. }
  15. }, "Thread synchronized block on Class").start();
  16. }

运行结果如下:

  1. Thread static synchronized method -> start synchronizedMethodOnClass
  2. Thread static synchronized method -> end synchronizedMethodOnClass
  3. Thread synchronized block on Class -> start synchronizedBlockOnClass
  4. Thread synchronized block on Class -> end synchronizedBlockOnClass

说明当线程 Thread static synchronized method 进入方法 synchronizedMethodOnClass
的时候,线程Thread synchronized block on Class 是不能进入synchronizedBlockOnClass 代码块的。

2、非 static 的 synchronized 方法和 synchronized (this) {} 同步代码块的锁都加在当前对象上面:

  1. public static void main(String[] args) {
  2. SynchronizedTest synchronizedTest = new SynchronizedTest();
  3.  
  4. new Thread(new Runnable() {
  5. @Override
  6. public void run() {
  7. synchronizedTest.synchronizedMethodOnThis(3000);
  8. }
  9. }, "Thread non-static synchronized method").start();
  10. new Thread(new Runnable() {
  11. @Override
  12. public void run() {
  13. synchronizedTest.synchronizedBlockOnThis(2000);
  14. }
  15. }, "Thread synchronized block on this").start();
  16. }

运行结果如下:

  1. Thread non-static synchronized method -> start synchronizedMethodOnThis
  2. Thread non-static synchronized method -> end synchronizedMethodOnThis
  3. Thread synchronized block on this -> start synchronizedBlockOnThis
  4. Thread synchronized block on this -> end synchronizedBlockOnThis

说明当线程 Thread non-static synchronized method 进入方法 synchronizedMethodOnThis
的时候,线程Thread synchronized block on this 是不能进入synchronizedBlockOnThis 代码块的。

3、当锁加在 MyClass.class 、 this 、 任意对象,这三种情况,起不到任何同步作用:

  1. public static void main(String[] args) {
  2. SynchronizedTest synchronizedTest = new SynchronizedTest();
  3.  
  4. new Thread(new Runnable() {
  5. @Override
  6. public void run() {
  7. synchronizedTest.synchronizedMethodOnThis(3000);
  8. }
  9. }, "Thread non-static synchronized method").start();
  10. new Thread(new Runnable() {
  11. @Override
  12. public void run() {
  13. SynchronizedTest.synchronizedMethodOnClass(2000);
  14. }
  15. }, "Thread static sybchronized method").start();
  16. new Thread(new Runnable() {
  17. @Override
  18. public void run() {
  19. synchronizedTest.synchronizedBlockOnObject(4000);
  20. }
  21. }, "Thread sybchronized block on other Object").start();
  22. }

运行结果如下:

  1. Thread non-static synchronized method -> start synchronizedMethodOnThis
  2. Thread static sybchronized method -> start synchronizedMethodOnClass
  3. Thread sybchronized block on other Object -> start synchronizedBlockOnObject
  4. Thread static sybchronized method -> end synchronizedMethodOnClass
  5. Thread non-static synchronized method -> end synchronizedMethodOnThis
  6. Thread sybchronized block on other Object -> end synchronizedBlockOnObject

说明当锁没有加在同一个对象上的时候,起不到线程间的同步作用。

Object中对内置锁进行操作的一些方法:

wait()系列:

wait()系列方法的作用是:使当前已经获得该对象锁的线程进入等待状态,并且释放该对象的锁。

notify()系列:

notify()系列方法的作用是:唤醒那些正在等待该对象锁的线程,使其继续运行。

基于wait() notify()机制,我们可以实现一个简易的生产者-消费者模型。

大体思路如下,一个生产者线程负责向一个仓库中存放(put)物品,一个消费者线程负责从仓库中取出(get)物品。

代码如下:

  1. public class Warehouse {
  2.  
  3. private Queue<Integer> queue;
  4. private int capacity;
  5.  
  6. public Warehouse(int capacity) {
  7. this.capacity = capacity;
  8. queue = new LinkedList();
  9. }
  10.  
  11. public synchronized void put(int num) {
  12. if (queue.size() >= capacity) {
  13. try {
  14. System.out.println(Thread.currentThread().getName() + " , put full wait");
  15. wait();
  16. } catch (InterruptedException e) {
  17. e.printStackTrace();
  18. }
  19. }
  20. queue.add(num);
  21. System.out.println(Thread.currentThread().getName() + " , put : " + num + " , queue -> " + queue);
  22. notifyAll();
  23. }
  24.  
  25. public synchronized int get() {
  26. if (queue.isEmpty()) {
  27. try {
  28. System.out.println(Thread.currentThread().getName() + " , get empty wait");
  29. wait();
  30. } catch (InterruptedException e) {
  31. e.printStackTrace();
  32. }
  33. }
  34. int num = queue.poll();
  35. System.out.println(Thread.currentThread().getName() + " , get : " + num + " , queue -> " + queue);
  36. notifyAll();
  37. return num;
  38. }
  39. }
  1. public static void main(String[] args) {
  2. Warehouse warehouse = new Warehouse(4);
  3. Random random = new Random();
  4.  
  5. new Thread(new Runnable() {
  6. @Override
  7. public void run() {
  8. while (true) {
  9. warehouse.put(random.nextInt(10));
  10. try {
  11. Thread.sleep(1000);
  12. } catch (InterruptedException e) {
  13. e.printStackTrace();
  14. }
  15. }
  16. }
  17. }, "生产者-01").start();
  18.  
  19. new Thread(new Runnable() {
  20. @Override
  21. public void run() {
  22. while (true) {
  23. warehouse.get();
  24. try {
  25. Thread.sleep(2000);
  26. } catch (InterruptedException e) {
  27. e.printStackTrace();
  28. }
  29. }
  30. }
  31. }, "消费者-01").start();
  32. }

运行结果如下:

  1. 生产者-01 , put : 5 , queue -> [5]
  2. 消费者-01 , get : 5 , queue -> []
  3. 生产者-01 , put : 7 , queue -> [7]
  4. 消费者-01 , get : 7 , queue -> []
  5. 生产者-01 , put : 9 , queue -> [9]
  6. 生产者-01 , put : 7 , queue -> [9, 7]
  7. 消费者-01 , get : 9 , queue -> [7]
  8. 生产者-01 , put : 0 , queue -> [7, 0]
  9. 生产者-01 , put : 5 , queue -> [7, 0, 5]
  10. 消费者-01 , get : 7 , queue -> [0, 5]
  11. 生产者-01 , put : 9 , queue -> [0, 5, 9]
  12. 生产者-01 , put : 6 , queue -> [0, 5, 9, 6]
  13. 消费者-01 , get : 0 , queue -> [5, 9, 6]
  14. 生产者-01 , put : 4 , queue -> [5, 9, 6, 4]
  15. 生产者-01 , put full wait
  16. 消费者-01 , get : 5 , queue -> [9, 6, 4]
  17. 生产者-01 , put : 6 , queue -> [9, 6, 4, 6]
  18. 生产者-01 , put full wait
  19. 消费者-01 , get : 9 , queue -> [6, 4, 6]
  20. 生产者-01 , put : 2 , queue -> [6, 4, 6, 2]
  21. 生产者-01 , put full wait
  22. 消费者-01 , get : 6 , queue -> [4, 6, 2]
  23. 生产者-01 , put : 9 , queue -> [4, 6, 2, 9]
  24. 生产者-01 , put full wait
  25. 消费者-01 , get : 4 , queue -> [6, 2, 9]
  26. 生产者-01 , put : 7 , queue -> [6, 2, 9, 7]
  27. 生产者-01 , put full wait
  28. 消费者-01 , get : 6 , queue -> [2, 9, 7]
  29. 生产者-01 , put : 2 , queue -> [2, 9, 7, 2]

Java内置锁的简单认识的更多相关文章

  1. Java内置锁和简单用法

    一.简单的锁知识 关于内置锁 Java具有通过synchronized关键字实现的内置锁,内置锁获得锁和释放锁是隐式的,进入synchronized修饰的代码就获得锁,走出相应的代码就释放锁. jav ...

  2. 深入理解Java内置锁和显式锁

    synchronized and Reentrantlock 多线程编程中,当代码需要同步时我们会用到锁.Java为我们提供了内置锁(synchronized)和显式锁(ReentrantLock)两 ...

  3. Java内置锁synchronized的实现原理

    简述Java中每个对象都可以用来实现一个同步的锁,这些锁被称为内置锁(Intrinsic Lock)或监视器锁(Monitor Lock). 具体表现形式如下: 1.普通同步方法,锁的是当前实例对象 ...

  4. 深入理解java内置锁(synchronized)和显式锁(ReentrantLock)

    多线程编程中,当代码需要同步时我们会用到锁.Java为我们提供了内置锁(synchronized)和显式锁(ReentrantLock)两种同步方式.显式锁是JDK1.5引入的,这两种锁有什么异同呢? ...

  5. Java内置锁synchronized的实现原理及应用(三)

    简述 Java中每个对象都可以用来实现一个同步的锁,这些锁被称为内置锁(Intrinsic Lock)或监视器锁(Monitor Lock). 具体表现形式如下: 1.普通同步方法,锁的是当前实例对象 ...

  6. Java 内置锁 重入问题

    阅读<Java并发编程实战>,遇到了一个问题 代码如下 /** * @auther draymonder */ public class Widget { public synchroni ...

  7. java内置锁实现锁住代码块方案(同一个对象或锁住整个类.class)

    我们看一个例子: class Demo { public synchronized void test() { System.out.println("test方法开始执行,当前线程为:&q ...

  8. Java内置锁synchronized的可重入性

    学习自 https://blog.csdn.net/aigoogle/article/details/29893667 对我很有帮助 感谢作者

  9. 七 内置锁 wait notify notifyall; 显示锁 ReentrantLock

    Object中对内置锁进行操作的一些方法: Java内置锁通过synchronized关键字使用,使用其修饰方法或者代码块,就能保证方法或者代码块以同步方式执行. 内置锁使用起来非常方便,不需要显式的 ...

随机推荐

  1. stm32f407使用Keil uV5建立工程日志

    目录结构 Common           ——包括延时函数等公用函数 STM32F4_FWLIB     ——固件库 Project             ——UV5工程相关文件 Main     ...

  2. Postman之命令测试

    前言 今天我们来学习一下Postman的命令行测试 1.先安装node.js ,https://nodejs.org/en/#home-downloadhead 2.安装cnpm npm instal ...

  3. 终于解决 k8s 集群中部署 nodelocaldns 的问题

    自从开始在 kubernetes 集群中部署 nodelocaldns 以提高 dns 解析性能以来,一直被一个问题困扰,只要一部署 nodelocaldns ,在 coredns 中添加的 rewr ...

  4. Java8尽管很香,你想过升级到Java11吗?会踩那些坑?

    目前最新JDK 11,Oracle会一直维护到2026年. Java11的新特性 1.更新支持到Unicode 10编码 Unicode 10(version 10.0 of the Unicode ...

  5. TCP/IP分为几层?各层的作用是什么?

    1. 应用层 2.传输层 3.网络层 4.网络接口层* 1.应用层 TCP/IP协议族在这一层面有着很多协议来支持不同的应用,许多大家所熟悉的基于Internet的应用的实现就离不开这些协议.如我们进 ...

  6. jQuery的动画以及扩展功能

    动画DOM及CSS操作 自定义动画 animate(最终css状态,时间) 这个最终css状态是一个对象 <!DOCTYPE html> <html lang="en&qu ...

  7. AndroidStudio跑起来第一个App时新手遇到的那些坑

    场景 当你看了一个Android教程,满心欢喜想要运行第一个HelloWorld时却发现,Android Studio新建的工程老是报错. 会编译不通过.运行按钮灰色.没有虚拟机,一个简简单单的Hel ...

  8. Blazor client-side + webapi (.net core 3.1) 添加jwt验证流程(非host)第二步 添加Identity

    添加Identity数据上下文 安装nuget包:Microsoft.AspNetCore.Identity.EntityFrameworkCore 创建ApplicationDbContext类 创 ...

  9. BloodHound可视化之域分析

    一.简介 BloodHound是一款将域内信息可视化的单页的web应用程序,是一款在域内进行信息收集的免费工具: bloodhound通过图与线的形式,将域内用户.计算机.组.会话.ACL以及域内所有 ...

  10. API网关服务:Spring Cloud Zuul

    最近在学习Spring Cloud的知识,现将API网关服务:Spring Cloud Zuul 的相关知识笔记整理如下.[采用 oneNote格式排版]