当前位置: 首页 > 编程日记 > 正文

JAVA多线程之Synchronized、wait、notify实例讲解

一、Synchronized

synchronized中文解释是同步,那么什么是同步呢,解释就是程序中用于控制不同线程间操作发生相对顺序的机制,通俗来讲就是2点,第一要有多线程,第二当多个线程同时竞争某个资源的时候会有先后顺序。在java中有三种写synchronized的方式:

第一种:写在普通方法的前面,这种表示对实例对象加锁第二种:写在静态方法前面,这种表示对类对象加锁第三种:写在代码块中,锁是Synchonized括号里配置的对象(可能是实例对象,也可能是类对象)

总体说来就2种,一种就是锁实例对象,一种锁类对象。

锁实例对象就是当多个线程同时操作这个实例对象(针对的是特定的实例对象)的时候必须先获取锁,如果无法获取锁,则必须处于等待状态,而和锁类对象区别是,当多个线程同时操作的时候,任何以这个类对象实例化的对象都要获取锁才能操作。

看下面的例子:

public class Synchronized_Test {public static void main(String[] args){Thread t1=new Thread(new MyRunnable());Thread t2=new Thread(new MyRunnable());t1.start();t2.start();}
}
class MyRunnable implements Runnable{private synchronized void synchMethodTest(){for(int i=0;i<10;i++)System.out.println(Thread.currentThread().getName()+"synchMethodTest: "+i);}public void run() {synchMethodTest();}
}

其输出结果为:

Thread-0synchMethodTest: 0
Thread-1synchMethodTest: 0
Thread-0synchMethodTest: 1
Thread-1synchMethodTest: 1
Thread-0synchMethodTest: 2
Thread-1synchMethodTest: 2
Thread-0synchMethodTest: 3
Thread-1synchMethodTest: 3
Thread-0synchMethodTest: 4
Thread-1synchMethodTest: 4
Thread-0synchMethodTest: 5
Thread-1synchMethodTest: 5
Thread-0synchMethodTest: 6
Thread-1synchMethodTest: 6
Thread-0synchMethodTest: 7
Thread-1synchMethodTest: 7
Thread-0synchMethodTest: 8
Thread-1synchMethodTest: 8
Thread-0synchMethodTest: 9
Thread-1synchMethodTest: 9

因为synchronized是写在普通方法前,是对特定的实例对象加锁,t1,t2为两个不同的实例,
所以他们在执行synchronized方法时并不会互相阻塞对方。

如果将synchronized方法改成static方法,那么就是针对类对象加锁,任何以这个类对象实例化的对象都要获取锁才能操作,
t1,t2虽然是两个不同的实例,但都是同一个类对象的实例,所以当t1取得锁开始执行synchronized方法后,就会阻塞t2,
t2需要取得锁之后才能执行,如下:

public class Synchronized_Test {public static void main(String[] args){Thread t1=new Thread(new MyRunnable());Thread t2=new Thread(new MyRunnable());t1.start();t2.start();}
}
class MyRunnable implements Runnable{private synchronized static void synchMethodTest(){for(int i=0;i<10;i++)System.out.println(Thread.currentThread().getName()+"synchMethodTest: "+i);}public void run() {synchMethodTest();} }

输出结果为:

Thread-0synchMethodTest: 0
Thread-0synchMethodTest: 1
Thread-0synchMethodTest: 2
Thread-0synchMethodTest: 3
Thread-0synchMethodTest: 4
Thread-0synchMethodTest: 5
Thread-0synchMethodTest: 6
Thread-0synchMethodTest: 7
Thread-0synchMethodTest: 8
Thread-0synchMethodTest: 9
Thread-1synchMethodTest: 0
Thread-1synchMethodTest: 1
Thread-1synchMethodTest: 2
Thread-1synchMethodTest: 3
Thread-1synchMethodTest: 4
Thread-1synchMethodTest: 5
Thread-1synchMethodTest: 6
Thread-1synchMethodTest: 7
Thread-1synchMethodTest: 8
Thread-1synchMethodTest: 9

t1执行完成,释放synchronized锁后,t2才能执行。如果在代码块中对类对象也是一样:

class MyRunnable implements Runnable{private void synchMethodTest(){synchronized (MyRunnable.class){for(int i=0;i<10;i++)System.out.println(Thread.currentThread().getName()+"synchMethodTest: "+i);}}public void run() {synchMethodTest();}
}

注意:
      类方法中,synchronized锁住的是对象this,只有调用同一个对象的方法才需要获取锁。同时,
同一个对象中所有加了synchronize的方法只能一次调用一个;
      静态方法中,synchronized锁的是整个类对象,类似于(X.class),该类中所有加了synchronized的静态方法,一次只能调用一个。
比较下面两个例子:

public class Synchronized_Test {public static void main(String[] args){Method method=new Method();Thread t1=new Thread(new MyRunnable1(method));Thread t2=new Thread(new MyRunnable2(method));t1.start();t2.start();}
}
class Method{public synchronized void Method1(){for(int i=0;i<10;i++)System.out.println(Thread.currentThread().getName()+" Method1: "+i);}public synchronized void Method2(){for(int i=0;i<10;i++)System.out.println(Thread.currentThread().getName()+" Method2 "+i);}
}
class MyRunnable1 implements Runnable{Method method;MyRunnable1(Method method){this.method=method;}public void run() {method.Method1();}
}
class MyRunnable2 implements Runnable{Method method;MyRunnable2(Method method){this.method=method;}public void run(){method.Method2();}
}

输出为:

Thread-0 Method1: 0
Thread-0 Method1: 1
Thread-0 Method1: 2
Thread-0 Method1: 3
Thread-0 Method1: 4
Thread-0 Method1: 5
Thread-0 Method1: 6
Thread-0 Method1: 7
Thread-0 Method1: 8
Thread-0 Method1: 9
Thread-1 Method2 0
Thread-1 Method2 1
Thread-1 Method2 2
Thread-1 Method2 3
Thread-1 Method2 4
Thread-1 Method2 5
Thread-1 Method2 6
Thread-1 Method2 7
Thread-1 Method2 8
Thread-1 Method2 9

因为锁住的整个Method对象,在t1执行method1时,给method对象加锁,当t2要执行method2时,因为时synchronized方法,
所以首先要取得method对象的锁,才能执行。

public class Synchronized_Test {public static void main(String[] args){Method method=new Method();Thread t1=new Thread(new MyRunnable1(method));Thread t2=new Thread(new MyRunnable2(method));t1.start();t2.start();}
}
class Method{public synchronized void Method1(){for(int i=0;i<10;i++)System.out.println(Thread.currentThread().getName()+" Method1: "+i);}public void Method2(){for(int i=0;i<10;i++)System.out.println(Thread.currentThread().getName()+" Method2 "+i);}
}
class MyRunnable1 implements Runnable{Method method;MyRunnable1(Method method){this.method=method;}public void run() {method.Method1();}
}
class MyRunnable2 implements Runnable{Method method;MyRunnable2(Method method){this.method=method;}public void run(){method.Method2();}
}

输出为:

Thread-0 Method1: 0
Thread-1 Method2 0
Thread-0 Method1: 1
Thread-1 Method2 1
Thread-0 Method1: 2
Thread-1 Method2 2
Thread-0 Method1: 3
Thread-1 Method2 3
Thread-0 Method1: 4
Thread-1 Method2 4
Thread-0 Method1: 5
Thread-1 Method2 5
Thread-0 Method1: 6
Thread-1 Method2 6
Thread-1 Method2 7
Thread-1 Method2 8
Thread-1 Method2 9
Thread-0 Method1: 7
Thread-0 Method1: 8
Thread-0 Method1: 9

从结果可以看到,t1并没有阻塞t2的运行,因为t2执行的method2方法不带synchronized,所以在执行时并不需要先获得method对象的锁,执行的过程中也就不存在阻塞的情况。

二、wait、notify和notifyAll

wait、notify、notifyAll是Object对象的属性,并不属于线程。我们先解释这三个的一个很重要的概念

wait:使持有该对象的线程把该对象的控制权交出去,然后处于等待状态(这句话很重要,也就是说当调用wait的时候会释放锁并处于等待的状态)notify:通知某个正在等待这个对象的控制权的线程可以继续运行(这个就是获取锁,使自己的程序开始执行,最后通过notify同样去释放锁,并唤醒正在等待的线程)notifyAll:会通知所有等待这个对象控制权的线程继续运行(和上面一样,只不过是唤醒所有等待的线程继续执行)Obj.wait()与Obj.notify()必须要与synchronized(Obj)一起使用,也就是wait与notify是针对已经获取了Obj锁的对象来进行操作

下面来看一个生产者消费者模型,他们有一个缓冲区,缓冲区有最大限制,当缓冲区满的时候,生产者是不能将产品放入到缓冲区里面的,当然,当缓冲区是空的时候,消费者也不能从中拿出来产品,这就涉及到了在多线程中的条件判断,java中提供了wait和notify方法,他们可以在线程不满足要求的时候让线程让出来资源等待,当有资源的时候再notify他们让他们继续工作。

import java.util.Date;
import java.util.LinkedList;
import java.util.List;
class EventStorage {private int maxSize;private List<date> storage;public EventStorage() {maxSize = 10;storage = new LinkedList<date>();}public synchronized void set() {while(storage.size() == maxSize) {try {wait();} catch (InterruptedException e) {e.printStackTrace();}}storage.add(new Date());System.out.println("Set: "+storage.size());notifyAll();}public synchronized void get() {while(storage.size() == 0) {try {wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("Get: "+storage.size()+" "+((LinkedList<date>)storage).poll());notifyAll();}
}
class Producer implements Runnable {private EventStorage storge;public Producer(EventStorage storage) {this.storge = storage;}public void run() {for(int i = 0; i < 100; i++) {storge.set();}}
}
class Consumer implements Runnable {private EventStorage storage;public Consumer(EventStorage storage) {this.storage = storage;}public void run() {for (int i = 0; i < 100; i++) {storage.get();}}
}
public class ProducerAndConsumer {public static void main(String[] args){EventStorage eventStorage=new EventStorage();Thread t1=new Thread(new Producer(eventStorage));Thread t2=new Thread(new Consumer(eventStorage));t1.start();t2.start();}
}

相关文章:

匹夫细说C#:委托的简化语法,聊聊匿名方法和闭包

0x00 前言 通过上一篇博客《匹夫细说C#&#xff1a;庖丁解牛聊委托&#xff0c;那些编译器藏的和U3D给的》的内容&#xff0c;我们实现了使用委托来构建我们自己的消息系统的过程。但是在日常的开发中&#xff0c;仍然有很多开发者因为这样或那样的原因而选择疏远委托&#xff…

20个案例详解 Pandas 当中的数据统计分析与排序

作者 | 俊欣来源 | 关于数据分析与可视化今天小编来给大家讲一下Pandas模块当中的数据统计与排序&#xff0c;说到具体的就是value_counts()方法以及sort_values()方法。value_counts()方法&#xff0c;顾名思义&#xff0c;主要是用于计算各个类别出现的次数的&#xff0c;而s…

zend studio 8安装与汉化

http://archive.eclipse.org/technology/babel/update-site/R0.8.0/helios正确操作&#xff1a;1、大家可以用这个地址作为更新源&#xff08;操作&#xff1a;菜单栏中window->property->Installation/update->update 添加这个地址&#xff0c;并打勾&#xff09; 2、…

分享一个电视节目API接口PHP调用代码

央视及各地卫视的电视节目时间表&#xff0c;包括本周及下周的电视节目内容 获取电视台分类 复制代码 获取电视频道 复制代码 获取电视节目的详情 复制代码 注意&#xff0c;该示例代码适用于 www.apishop.net网站下API 使用该产品前&#xff0c;您需要通过 https://…

用Zend Stuido 的WSDL编辑器

文件->新建->其他->Webservice->WSDL新建WSDL下一步点完成生成如下wsdlTestSoapSoap下面填写php webService 如myservice.phpNewOption:添加方法。WebService里需要提供给别人调用的方法名input &#xff1a;设置输入参数名和类型output&#xff1a;设置返回值。Ad…

坐地铁就能学会的3种非常有趣的 Python 玩法

作者 | 黄伟呢来源 | 数据分析与统计学之美本文说明为什么要学习python&#xff1f;是因为不仅很多工作需要用到python&#xff0c;同时我们可以利用python做很多好玩儿的事儿。比如说下面的3种用法&#xff1a;1.利用python给小猪佩奇换背景色&#xff1b;2.利用python将小猪佩…

asp.net input怎么获取值

前台&#xff1a; <input type"hidden" name"content" value"content"> 后台&#xff1a; Request.Form["content"].ToString(); 切记&#xff1a;name不能缺少&#xff0c;id可由可无。>如有问题&#xff0c;请联系我&…

koa2 简单了解

为什么80%的码农都做不了架构师&#xff1f;>>> 1.安装 $ nvm install 7 $ npm i koa $ node my-koa-app.js2.简介 基于ES7开发的koa2&#xff0c;和koa 1相比&#xff0c;koa2完全使用Promise并配合async来实现异步。 app.use(async (ctx, next) > {await next…

亚洲最大的元宇宙平台,体验在豪宅里开party

整理 | 禾木木 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; 想象一下&#xff0c;你刚刚得到了你愿望清单上一直想拥有的生活方式&#xff0c;电视、可提高您生活质量的家用电器以及最新款时尚智能手机。现在&#xff0c;如果我们告诉你可以使用这些创新产品来装…

html5知识点补充—hgroup元素的使用

使用hgroup元素组合标题 使用新的HTML5元素hgroup&#xff0c;可以为header元素添加更多的信息。 这个元素用来对多个相关联的h1~h6标题进行分组。如果你的网站有副标题&#xff0c;可以使用hgroup元素。虽然hgroup是一个有效的分组选项&#xff0c;但是它主要是用来告知文档大…

Linux下nginx支持.htaccess文件实现伪静态的方法!

在Google上搜索的资料很多人都说nginx目前不支持.htaccess文件&#xff0c;我按照nginx的规则试验了一下&#xff0c;结果发现nginx是完全支持.htaccess文件的&#xff01; 方法如下&#xff1a;1. 在需要使用.htaccess文件的目录下新建一个.htaccess文件&#xff0c;如本人的一…

查看mysql的编码格式

1.查看数据库编码格式 show variables like character_set_database; 2.查看数据表的编码格式 show create table <表名>; 3.创建数据库时指定数据库的字符集 create database <数据库名> character set utf8; 4.创建数据表时指定数据表的编码格式 create table tb…

undefined reference to `libiconv_open 无法编译PHP libiconv

原文&#xff1a;http://hi.baidu.com/ostech/blog/item/a63f9b0dabed1ae7ab6457d0.html./configure --with-mysql/backup/mysql --with-freetype-dir --with-jpeg-dir --with-png-dir --with-zlib --with-curl --with-gd --enable-gd-native-ttf --with-apxs2/usr/local/apach…

Meta 被爆暂停 AR/VR 操作系统项目,元宇宙能否推进?

编译 | 禾木木 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; 据 The Information 的近日报道&#xff0c;Meta 已经停止了一直以来为 AR 和 VR 操作系统的努力。在11月就通知了负责 VR 和 AR 设备的实验室的员工&#xff0c;表示将要停止 XROS 相关的开发工作。 …

DevOps:怎么实现源代码注释和系统文档的自动化更新?

【编者按】计算机软件传统定义为&#xff1a;软件是计算机系统中与硬件相依存的另一部分&#xff0c;软件包括程序、数据及其相关文档的完整集合。然而在时下的开发中&#xff0c;文档的合规性往往被忽视的干干净净。本文由 Todd Waits 撰写&#xff0c;讲述应用程序文档化所遭…

在Kubernetes v1.8中使用RBAC

Kubernetes 1.8一个重要里程碑是推出了基于角色的访问控制(RBAC)授权&#xff0c;在这个版本中被提升为GA。RBAC是一种控制访问Kubernetes API的机制&#xff0c;因为在1.6中推出beta版&#xff0c;许多Kubernetes集群和配置策略在默认情况下都启用了它。展望未来&#xff0c;我…

Java String.substring内存泄露?

2019独角兽企业重金招聘Python工程师标准>>> String可以说是最常用的Java类型之一了&#xff0c;但是最近听说JDK6里面String.substring存在内存泄露的bug&#xff0c;伙惊呆&#xff01;一起来看看到底是啥情况吧。 这个是可以导致Exception in thread "main&…

第二弹,坐地铁就能学会的3种「非常有趣」的 Python 玩法

作者 | 黄伟呢来源 | 数据分析与统计学之美本文说明为什么要学习python&#xff1f;是因为不仅很多工作需要用到python&#xff0c;同时我们可以利用python做很多好玩儿的事儿。比如说下面的3种用法&#xff1a;1.利用python给小猪佩奇换背景色&#xff1b;2.利用python将小猪佩…

php比较长的configure

原先的字串./configure --prefix/usr/local/php --with-apxs2/usr/local/apache2/bin/apxs --enable-zip --enable-calendar --with-mysql/usr/local/mysql --with-pdo-mysql/usr/local/mysql --with-iconv/usr/local/libiconv --with-curl/usr/local/curl --with-gd/usr/local…

用mpvue实现的微信小程序版cnode社区

五一放假&#xff0c;没出去玩&#xff0c;想熟悉下vue的开发流程&#xff0c;又想体验下mpvue&#xff0c;于是写了个练手项目。一个用mpvue实现的cnode微信小程序版。 代码在仓库。欢迎各位star、fork、issue、pr。目前已经完成了百分之80的功能。个人感觉这个项目还是非常适…

PHP编译安装

#wget http://museum.php.net/php5/php-5.2.6.tar.gz &#xff08;下载php源码&#xff09; http://cn.php.net/releases/ 可以找到 #tar zxvf php-5.2.6.tar.gz #cd php-5.2.6 #./configure --prefix/usr/local/php --with-mysql/usr/local/mysql --with-apxs2/usr/local/apa…

Python 办公自动化,一键给PDF文件加密,超方便

作者 | 欣一来源 | Python爱好者集中营今天给大家做一个给PDF文件加密的GUI界面(图形用户界面)&#xff0c;方便现在的一些上班族白领们使用&#xff0c;尤其是需要给一些比较重要的PDF文件加密的时候&#xff0c;下面我们来看具体的步骤给PDF文件加密首先我们需要清楚的是如何…

YUM安装多个(多实例) Mysql

2019独角兽企业重金招聘Python工程师标准>>> 这里使用的是MYSQL的percona分支 先安装repo包 yum install percona-release-0.0-1.x86_64.rpm -y 想安装5.6的把5.5替换就行了,5.6的太耗内存了-。- yum install Percona-Server-server-55.x86_64 Percona-Server-clien…

scala可变长度参数函数

2019独角兽企业重金招聘Python工程师标准>>> scala可变长度参数函数只需要在参数列表的最后放一个星号&#xff0c;实验如下&#xff1a; def main (args:Array[String]){argsfun("Runoob", "Scala", "Python")} def argsfun(args:St…

3000 字推荐一个可视化神器,50 行 Python 代码制作数据大屏

作者 | 俊欣来源 | 关于数据分析与可视化今天小编给大家分享一个制作数据大屏的工具&#xff0c;非常的好用&#xff0c;100行左右的Python代码就可以制作出来一个完整的数据大屏&#xff0c;并且代码的逻辑非常容易理解。PywebIO介绍Python当中的PywebIO模块可以帮助开发者在不…

使用Varnish+ESI实现静态页面的局部缓存

页面静态化是搭建高性能网站必用的招式之一&#xff0c;页面静态化可以有效提升系统响应速度&#xff0c;同时也有利于搜索引擎优化。但在页面静态化后&#xff0c;静态页面之间包含&#xff08;例如所有的静态页面包含页头、页脚&#xff09;以及静态页面中的局部信息的动态更…

The Apply method of function object

2019独角兽企业重金招聘Python工程师标准>>> http://webreference.com As explained in the previous page, JavaScript 1.3 includes two new methods for the Function object, call() andapply(). The apply() method is a variation on the call() method. The …

资源 | 100+个自然语言处理数据集大放送,再不愁找不到数据!

奉上100多个按字母顺序排列的开源自然语言处理文本数据集列表&#xff08;原始未结构化的文本数据&#xff09;&#xff0c;快去按图索骥下载数据自己研究吧&#xff01; 数据集 Apache软件基金会公开邮件档案&#xff1a;截止到2011年7月11日全部公开可用的Apache软件基金会邮…

Java中ArrayList源码分析

一、简介 ArrayList是一个数组队列&#xff0c;相当于动态数组。每个ArrayList实例都有自己的容量&#xff0c;该容量至少和所存储数据的个数一样大小&#xff0c;在每次添加数据时&#xff0c;它会使用ensureCapacity()保证容量能容纳所有数据。 1.1、ArrayList 的继承与实现接…

介绍三种绘制时间线图的方法

作者 |周萝卜来源 |萝卜大杂烩今天我们再来分享几种不同的制作方法&#xff0c;大家可以自行比较下各种方法的优劣。Matplotlib 制作Matplotlib 作为 Python 家族最为重要的可视化工具&#xff0c;其基本的 API 以及绘制流程还是需要掌握的。尤其是该库的灵活程度以及作为众多工…