synchronized关键字

2人阅读 评论(0) 收藏 举报
分类:

synchronized关键字,代表这个方法加锁,相当于不管哪一个线程(例如线程A),运行到这个方法时,都要检查有没有其它线程B(或者C、D等)正在用这个方法,有的话要等正在使用synchronized方法的线程B(或者C、D)运行完这个方法后再运行此线程A,没有的话,直接运行。它包括两种用法:synchronized方法和synchronized块。

synchronized 方法

声明是为了定义变量的作用范围和作用域

通过在方法声明中加入synchronized关键字来声明synchronized方法。如:

publicsynchronizedvoidaccessVal(intnewVal);

synchronized方法控制对类成员变量的访问:每个类实例对应一把锁,每个synchronized方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为synchronized的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为synchronized)。

在Java中,不光是类实例,每一个类也对应一把锁,这样我们也可将类的静态成员函数声明为synchronized,以控制其对类的静态成员变量的访问。

synchronized方法的缺陷:若将一个大的方法声明为synchronized将会大大影响效率,典型地,若将线程类的方法run()声明为synchronized,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何synchronized方法的调用都永远不会成功。当然我们可以通过将访问类成员变量的代码放到专门的方法中,将其声明为synchronized,并在主方法中调用来解决这一问题,但是Java为我们提供了更好的解决办法,那就是synchronized块。

synchronized 块

通过synchronized关键字来声明synchronized块。语法如下:

synchronized(syncObject){

//允许访问控制的代码

}

synchronized块是这样一个代码块,其中的代码必须获得对象syncObject(如前所述,可以是类实例或类)的锁方能执行,具体机制同前所述。由于可以针对任意代码块,且可任意指定上锁的对象,故灵活性较高。

一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。

二、然而,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。

三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。

四、第三个例子同样适用其它同步代码块,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。

五、以上规则对其它对象锁同样适用.

1.方法声明时使用,放在范围操作符(public等)后,其返回类型声明(void等)之前。即一次只能有一个线程进入该方法,其他线程要想在此时调用该方法,只能排队等候,当前线程(就是在synchronized方法内部的线程)执行完该方法后,别的线程才能进入。

例如:

public synchronized void synMethod() {

//方法体

}

2.对某一代码块使用,synchronized后跟括号,括号里是变量,这样,一次只有一个线程进入该代码块。例如:

public int synMethod(Object a1){

synchronized(Object) {

//一次只能有一个线程进入

}

}

3.synchronized后面括号里是一对象,此时,线程获得的是对象锁。例如:

public class MyThread implements Runnable {

public static void main(String args[]) {

MyThread mt = new MyThread();

Thread t1 = new Thread(mt, "t1");

Thread t2 = new Thread(mt, "t2");

Thread t3 = new Thread(mt, "t3");

Thread t4 = new Thread(mt, "t4");

Thread t5 = new Thread(mt, "t5");

Thread t6 = new Thread(mt, "t6");

t1.start();

t2.start();

t3.start();

t4.start();

t5.start();

t6.start();

}

public void run() {

synchronized (this) {

System.out.println(Thread.currentThread().getName());

}

}

}

对于3,如果线程进入,则得到对象锁,那么别的线程在该类所有对象上的任何操作都不能进行。在对象级使用锁通常是一种比较粗糙的方法。为什么要将整个对象都上锁,而不允许其他线程短暂地使用对象中其他同步方法来访问共享资源?如果一个对象拥有多个资源,就不需要只为了让一个线程使用其中一部分资源,就将所有线程都锁在外面。由于每个对象都有锁,可以如下所示使用虚拟对象来上锁:

class FineGrainLock {

MyMemberClass x, y;

Object xlock = new Object(), ylock = new Object();

public void foo() {

synchronized(xlock) {

//access x here

}

//do something here - but don‘t use shared resources

synchronized(ylock) {

//access y here

}

}

public void bar() {

synchronized(this) {

//access both x and y here

}

//do something here - but don‘t use shared resources

}

}

4.synchronized后面括号里是类。例如:

class ArrayWithLockOrder{

private static long num_locks = 0;

private long lock_order;

private int[] arr;

public ArrayWithLockOrder(int[] a)

{

arr = a;

synchronized(ArrayWithLockOrder.class) {//-----------------------------------------这里

num_locks++; // 锁数加 1。

lock_order = num_locks; // 为此对象实例设置唯一的 lock_order。

}

}

public long lockOrder()

{

return lock_order;

}

public int[] array()

{

return arr;

}

}

class SomeClass implements Runnable

{

public int sumArrays(ArrayWithLockOrder a1,

ArrayWithLockOrder a2)

{

int value = 0;

ArrayWithLockOrder first = a1; // 保留数组引用的一个

ArrayWithLockOrder last = a2; // 本地副本。

int size = a1.array().length;

if (size == a2.array().length)

{

if (a1.lockOrder() > a2.lockOrder()) // 确定并设置对象的锁定

{ // 顺序。

first = a2;

last = a1;

}

synchronized(first) { // 按正确的顺序锁定对象。

synchronized(last) {

int[] arr1 = a1.array();

int[] arr2 = a2.array();

for (int i=0; i value += arr1[i] + arr2[i];

}

}

}

return value;

}

public void run() {

//...

}

}

对于4,如果线程进入,则线程在该类中所有操作不能进行,包括静态变量静态方法,实际上,对于含有静态方法和静态变量的代码块的同步,我们通常用4来加锁。

以上4种之间的关系:

锁是和对象相关联的,每个对象有一把锁,为了执行synchronized语句,线程必须能够获得synchronized语句中表达式指定的对象的锁,一个对象只有一把锁,被一个线程获得之后它就不再拥有这把锁,线程在执行完synchronized语句后,将获得锁交还给对象。

在方法前面加上synchronized修饰符即可以将一个方法声明为同步化方法。同步化方法在执行之前获得一个锁。如果这是一个类方法,那么获得的锁是和声明方法的类相关的Class类对象的锁。如果这是一个实例方法,那么此锁是this对象的锁。synchronzied块后面跟类的具体详细例子:

public class DB2_JDBCFactory {

private static DB2_JDBCFactory instance = null;

public static final ThreadLocal = new ThreadLocal();

private DB2_JDBCFactory() {

}

public static DB2_JDBCFactory getInstance() {

if(instance == null) {

synchronized(DB2_JDBCFactory.class) { //synchronized后面跟一个类

instance = new DB2_JDBCFactory();

}

}

return instance;

}

public Connection getConnection_JNDI_localhost(){

Connection c = (Connection) threadLocal.get();

try {

if (c == null || c.isClosed()) {

InitialContext ctx = new InitialContext();

DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/localhost");

c = ds.getConnection();

threadLocal.set(c);

}

} catch (Exception ex) {

System.err.println("getConnection_JNDI Initial failed. " + ex);

return null;

}

return c;

}

} 外面的对象访问这个类的 需要通过调用它的getInstance()





来源百度文库


查看评论

java中synchronized关键字的认识&记录

通过具体项目中在线程间同步遇到的问题(app无响应ANR)来阐述synchronized关键字的使用场景。...
  • bibingyan
  • bibingyan
  • 2017-02-21 20:27:57
  • 461

多线程之synchronized关键字详解

synchronized关键字用于多线程访问程序中的共享资源时实现顺序同步访问资源。可以修饰方法或者代码块。而且关键字synchronized取得的锁都是对象锁,什么叫对象锁呢,就是一个对象产生一把锁...
  • Trigl
  • Trigl
  • 2016-04-15 20:23:17
  • 2852

Java基础-synchronized关键字的用法

顾名思义是用于同步互斥的作用的。 这里精简的记一下它的使用方法以及
  • cq361106306
  • cq361106306
  • 2014-08-21 21:02:20
  • 4771

Java线程同步中关键字synchronized简述

Java线程同步中关键字synchronized简述 一、作用: synchronized关键字通过修饰一个方法或者声明一个代码块,从而产生一个同步对象锁以及对应的同步代码块。每当...
  • beiyus
  • beiyus
  • 2015-10-14 13:40:49
  • 2067

java的关键字synchronized用法总结

第一篇:   使用synchronized   在编写一个类时,如果该类中的代码可能运行于多线程环境下,那么就要考虑同步的问题。在Java中内置了语言级的同步原语--synchronized,...
  • u010586698
  • u010586698
  • 2016-06-27 21:04:35
  • 1433

关于java synchronized关键字的一些理解

看了java编程思想的并发这一章,发现对于synchronized关键字理解不够到位,看了其他人的博客,加深了一些理解:http://www.cnblogs.com/GnagWang/archive/...
  • yxl0011
  • yxl0011
  • 2016-12-20 16:05:33
  • 289

synchronized关键字的4种用法

1.方法声明时使用,放在范围操作符(public等)之后,返回类型声明(void等)之前.这时,线程获得的是成员锁,即一次只能有一个线程进入该方法,其他线程要想在此时调用该方法,只能排队等候,当前线程...
  • qq441568267
  • qq441568267
  • 2016-11-21 14:41:35
  • 354

深入理解Java并发4——synchronized关键字

一 概述 由上一篇博客(http://blog.csdn.net/xiaowang627/article/details/60584428),我们已经体验到synchronized关键字的强大之处...
  • xiaowang627
  • xiaowang627
  • 2017-03-07 13:36:35
  • 333

Java关于Synchronized关键字在不同位置使用的理解

Java中的Syncronized关键字可以用来修饰同步方法:像这样synchronized void f() {/*body*/}和同步语句块:像这样synchronized(object){/*b...
  • yuyuanhuang
  • yuyuanhuang
  • 2015-03-10 15:58:09
  • 2534

Synchronized关键字详解

多线程的同步机制对资源进行加锁,使得在同一个时间,只有一个线程可以进行操作,同步用以解决多个线程同时访问时可能出现的问题。   同步机制可以使用synchronized关键字实现。   当...
  • u010408365
  • u010408365
  • 2014-12-17 16:02:03
  • 2136
    个人资料
    等级:
    访问量: 221
    积分: 143
    排名: 113万+
    文章分类
    文章存档