synchronized作用范围及用法
1、多线程的同步:
在多线程中,可能有多个线程试图访问一个有限的资源,必须预防这种情况的发生。所以引入了同步机制:在线程使用一个资源时为其加锁,这样其他的线程便不能访问那个资源了,直到解锁后才可以访问。
成员变量:
如果一个变量是成员变量,那么多个线程对同一个对象的成员变量进行操作,这多个线程是共享一个成员变量的。
局部变量:
如果一个变量是局部变量,那么多个线程对同一个对象进行操作,每个线程都会有一个该局部变量的拷贝。他们之间的局部变量互不影响。
实现了Runnable的线程类:
class MyThread3 implements Runnable{
//两个线程操作同一个对象,共享成员变量
//int i;
@Override
public void run() {
//两个线程操作同一个对象,各自保存局部变量的拷贝
int i = 0;
while(i<100){
System.out.println(i);
i++;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}在main方法中用两个线程操作同一个对象:
public static void main(String[] args) {
MyThread3 myThread = new MyThread3();
//下面两个线程对同一个对象(Runnable的实现类对象)进行操作
Thread thread = new Thread(myThread);
Thread thread2 = new Thread(myThread);
//各自保存局部变量的拷贝,互不影响,输出200个数字
thread.start();
thread2.start();
}
这里如果把i变成成员变量,则输出100个数字。
下面举个例子,两个线程共用一个Number对象,通过Number类的getNumber方法获取数据,读取数据并改写时,发现了重复读操作:
首先创建一个Number类:
class Number{
private int number = 10;
public String getNumber(int i){
if(number > 0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
number -= i;
return "取出"+i+"成功,剩余数量:"+number;
}
return "取出"+i+"失败,剩余数量:"+number;
}
}线程类,在线程类中的私有属性包含了Number类的引用:
class MyThread4 extends Thread{
//两个线程操作同一个对象,共享成员变量
Number number;
public MyThread4(Number number){
this.number = number;
}
@Override
public void run() {
System.out.println(number.getNumber(8));
}
}在main函数中创建两个线程类,包含了同一个Number类实例的引用:
public static void main(String[] args) {
Number number = new Number();
//两个线程操作同一个对象,共享对象number的成员变量number
MyThread4 myThread = new MyThread4(number);
MyThread4 myThread2 = new MyThread4(number);
myThread.start();
myThread2.start();
}
这样,当第一个线程读取Number中的number变量时先保存下来再休眠0.1秒,然后第二个线程再读取number变量并保存,此时两个线程保存了同样的数字,在修改时,也就导致修改了同一个数字两次。
使用synchronized关键字,该关键字修饰的方法叫做同步方法。
Java中每个对象都有一个锁或者称为监视器,当访问某个对象的synchronized方法时,表示将该对象上锁,而不仅仅是为该方法上锁。
这样如果一个对象的synchronized方法被某个线程执行时,其他线程无法访问该对象的任何synchronized方法(但是可以调用其他非synchronized的方法)。直至该synchronized方法执行完。
当调用一个对象的静态synchronized方法时,它锁定的并不是synchronized方法所在的对象,而是synchronized方法所在对象对应的Class对象。这样,其他线程就不能调用该类的其他静态synchronized方法了,但是可以调用非静态的synchronized方法。
结论:执行静态synchronized方法锁方法所在对象,执行非静态synchronized方法锁方法所在对象对应的Class对象。
下面是多线程调用静态的方法的例子,由于锁定了方法所在对象对应的Class对象,其他线程无法调用该方法所在对象其他的静态synchronized方法:
/**
* 定义一个类,包含了线程类需要调用的方法
*/
class Compute1{
//这时如果某个线程调用该方法,
//将锁定synchronized方法所在对象对应的class对象,
//而不是锁定synchronized方法所在对象
public synchronized static void execute(){
for(int i = 0; i<100; i++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("compute1:execute1 " + i++);
}
}
public synchronized static void execute2(){
for(int i = 0; i<100; i++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("compute1:execute2 " + i++);
}
}
}main方法中两个线程分别调用同一个对象的两个static synchronized方法: public static void main(String[] args) {
Compute1 com = new Compute1();
Thread thread1 = new Thread1(com);
Thread thread2 = new Thread2(com);
thread1.start();
thread2.start();
}
一次只能调用一个静态方法,直到执行完成。
通过使用synchronized同步代码块,锁定一个对象,该对象作为可执行的标志从而达到同步的效果:
/**
* 定义一个类,包含了线程类需要调用的方法
*/
class Compute1{
//通过同步代码块锁定object1对象进行锁定了其他同样的synchronized代码块
private Object object1 = new Object();
public void execute(){
synchronized(object1){
for(int i = 0; i<100; i++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("compute1:execute1 " + i++);
}
} }
public synchronized void execute2(){
synchronized(object1){
for(int i = 0; i<100; i++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("compute1:execute2 " + i++);
}
}
}
}
如果想要使用synchronized同步代码块达到和使用synchronized方法同样的效果,可以锁定this引用:
synchronized(this){
…
}
synchronized同步代码块只是锁定了该代码块,代码块外面的代码还是可以被访问的。
synchronized方法是粗粒度的并发控制,某一个时刻只能有一个线程执行该synchronized方法。
synchronized同步代码块是细粒度的并发控制,只会将块中的代码同步,代码块之外的代码可以被其他线程同时访问。
synchronized作用范围及用法的更多相关文章
- java中synchronized关键字的用法
在java编程中,经常需要用到同步,而用得最多的也许是synchronized关键字了,下面看看这个关键字的用法. 因为synchronized关键字涉及到锁的概念,所以先来了解一些相关的锁知识. j ...
- Java关键字-----------------java中synchronized关键字的用法
在java编程中,经常需要用到同步,而用得最多的也许是synchronized关键字了,下面看看这个关键字的用法. 因为synchronized关键字涉及到锁的概念,所以先来了解一些相关的锁知识. j ...
- Java基础-synchronized关键字的用法(转载)
synchronized--同步 顾名思义是用于同步互斥的作用的. 这里精简的记一下它的使用方法以及意义: 当synchronized修饰 this或者非静态方法或者是一个实例的时候,所同步的锁是加在 ...
- synchronized关键字的用法总结
synchronized关键字主要有以下这3种用法: 修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁 修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁 修饰代 ...
- 内置锁(一)synchronized 介绍与用法
一.synchronized 的介绍 synchronized 是 Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码,而这段代码也被称 ...
- java实现Synchronized锁的用法
Java线程同步中的一个重要的概念synchronized. synchronized是java的关键字,是一种同步锁,它作用的对象有以下几种: ①作用在代码块上.该代码块称为同步代码块,作用范围是大 ...
- @synchronized(self)的用法 小结
@synchronized() 的作用是创建一个互斥锁,保证在同一时间内没有其它线程对self对象进行修改,起到线程的保护作用, 一般在公用变量的时候使用,如单例模式或者操作类的static变量中使用 ...
- java 中关于synchronized的通常用法
package j2se.thread.test; /*** * synchronized(class)很特别,它会让另一个线程在任何需要获取class做为monitor的地方等待. * class与 ...
- 关于@synchronized(self)的用法
@synchronized 的作用是创建一个互斥锁,保证此时没有其它线程对self对象进行修改.这个是objective-c的一个锁定令牌,防止self对象在同一时间内被其它线程访问,起到线程的保护作 ...
随机推荐
- 图解TCP/IP读书笔记(三)
第三章.数据链路 数据链路层是计算机网络最基本的内容. 数据链路层的协议定义了通过通信媒介互连的设备之间传输的规范. 一.数据链路相关技术 1.MAC地址 关于MAC地址的几个要点: ①MAC地址长度 ...
- Linux配置自建 YUM 软件存储库
yum软件仓库的搭建方式有三种,分别是本地yum源,网络yum源,第三方软件仓库. 以下示例演示了搭建本地yum仓库的方法: 1. 删除 /etc/yum.repos.d/dvd.repo 这个仓库文 ...
- JBoss 性能优化(解决Jboss内存紧张的问题)
修改$JBOSS_HOME/bin/run.conf文件 JAVA_OPTS="-Xms 520m -Xmx 1220m -Xss 15120k +XX:AggressiveHeap&q ...
- Data Flow ->> Slow Changing Dimension
这里简单讲下SCD 在讲之前贴上两个有用的链接地址.作者的两篇文件讲解了SCD是什么以及应用 http://www.cnblogs.com/biwork/p/3363749.html http://w ...
- C# 获取打印机状态
public static string GetPrinterStatus(string PrinterName) { int intValue = GetPrinterStatusInt ...
- boost静态链接的问题 -lgcc_s
在使用gcc/g++ 编译程序时我们希望指向一些库是使用静态的链接方式. 另外的一些是动态的方式. 我以boost 为例. 如果我们要使用静态库则是这样的: # g++ main.cpp -lpthr ...
- guidelines for contributing Hearthstone-Deck-Tracker
https://github.com/Epix37/Hearthstone-Deck-Tracker/blob/master/CONTRIBUTING.md Coding style Always u ...
- Top 10 steps to optimize data access in SQL Server
2009年04月28日 Top 10 steps to optimize data access in SQL Server: Part I (use indexing) 2009年06月01日 To ...
- 10.10 dos实验
一. 实验目的 (1)认识DOS: (2)掌握命令解释程序的原理: (3)掌握简单的DOS调用方法: (4)掌握C语言编程初步. 二. 实验内容和要求 编写类似于DOS,UNIX的命令行解释程序 (1 ...
- 浅析JavaScript之Function类型
JavaScript中的函数实际上是对象,每个函数都是Function类型的实例,而且都与其他引用类型一样具有属性和方法.由于函数是对象,因此函数名实际上只是指向函数对象的指针,保存函数在堆内存中的地 ...