使用synchronized的方法和作用

本文详细解析了Java中的synchronized关键字,包括其作用域、用法及注意事项。探讨了synchronized在方法级别和代码块级别的应用,并提供了示例代码。强调了正确使用synchronized对于确保多线程环境下数据一致性和安全性的重要性。
转自http://blog.youkuaiyun.com/soartju/article/details/2840491
 
在java编程思想中对synchronized的一点解释:
1、synchronized关键字的作用域有二种: 
1)是某个对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。这时,不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法; 
2)是某个类的范围,synchronized static aStaticMethod{}防止多个线程同时访问这个类中的synchronized static 方法。它可以对类的所有对象实例起作用。 

2、除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。用法是: synchronized(this){/*区块*/},它的作用域是当前对象; 

3、synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法; 

 
----------------------------------------------------------------------------
java里面synchronized用法
 

//synchronized的一个简单例子
public class TextThread 
{
 /**
  * @param args
  */
 public static void main(String[] args) 
 {
  // TODO 自动生成方法存根
        TxtThread tt = new TxtThread();
        new Thread(tt).start();
        new Thread(tt).start();
        new Thread(tt).start();
        new Thread(tt).start();
 }
}
class TxtThread implements Runnable
{
 int num = 100;
 String str = new String();
 public void run()
 {
  while (true)
  {
   synchronized(str)
   {
   if (num>0)
   {
    try
    {
     Thread.sleep(10);
    }
    catch(Exception e)
    {
     e.getMessage();
    }
    System.out.println(Thread.currentThread().getName()+ "this is "+ num--);
   }
   }
  }
 }
}


上面的例子中为了制造一个时间差,也就是出错的机会,使用了Thread.sleep(10)


Java对多线程的支持与同步机制深受大家的喜爱,似乎看起来使用了synchronized关键字就可以轻松地解决多线程共享数据同步问题。到底如何?――还得对synchronized关键字的作用进行深入了解才可定论。

总的说来,synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。如果再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class literals(类名称字面常量)身上。

在进一步阐述之前,我们需要明确几点:

A.无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。

B.每个对象只有一个锁(lock)与之相关联。

C.实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。

接着来讨论synchronized用到不同地方对代码产生的影响:

 

假设P1、P2是同一个类的不同对象,这个类中定义了以下几种情况的同步块或同步方法,P1、P2就都可以调用它们。

 

1.  把synchronized当作函数修饰符时,示例代码如下:

Public synchronized void methodAAA()

{

//….

}

这也就是同步方法,那这时synchronized锁定的是哪个对象呢?它锁定的是调用这个同步方法对象。也就是说,当一个对象P1在不同的线程中执行这个同步方法时,它们之间会形成互斥,达到同步的效果。但是这个对象所属的Class所产生的另一对象P2却可以任意调用这个被加了synchronized关键字的方法。

上边的示例代码等同于如下代码:

public void methodAAA()

{

synchronized (this)      //  (1)

{

       //…..

}

}

 (1)处的this指的是什么呢?它指的就是调用这个方法的对象,如P1。可见同步方法实质是将synchronized作用于object reference。――那个拿到了P1对象锁的线程,才可以调用P1的同步方法,而对P2而言,P1这个锁与它毫不相干,程序也可能在这种情形下摆脱同步机制的控制,造成数据混乱:(

2.同步块,示例代码如下:

            public void method3(SomeObject so)

              {

                     synchronized(so)

{

       //…..

}

}

这时,锁就是so这个对象,谁拿到这个锁谁就可以运行它所控制的那段代码。当有一个明确的对象作为锁时,就可以这样写程序,但当没有明确的对象作为锁,只是想让一段代码同步时,可以创建一个特殊的instance变量(它得是一个对象)来充当锁:

class Foo implements Runnable

{

       private byte[] lock = new byte[0];  // 特殊的instance变量

    Public void methodA()

{

       synchronized(lock) { //… }

}

//…..

}

注:零长度的byte数组对象创建起来将比任何对象都经济――查看编译后的字节码:生成零长度的byte[]对象只需3条操作码,而Object lock = new Object()则需要7行操作码。

3.将synchronized作用于static 函数,示例代码如下:

      Class Foo

{

public synchronized static void methodAAA()   // 同步的static 函数

{

//….

}

public void methodBBB()

{

       synchronized(Foo.class)   //  class literal(类名称字面常量)

}

       }

   代码中的methodBBB()方法是把class literal作为锁的情况,它和同步的static函数产生的效果是一样的,取得的锁很特别,是当前调用这个方法的对象所属的类(Class,而不再是由这个Class产生的某个具体对象了)。

记得在《Effective Java》一书中看到过将 Foo.class和 P1.getClass()用于作同步锁还不一样,不能用P1.getClass()来达到锁这个Class的目的。P1指的是由Foo类产生的对象。

可以推断:如果一个类中定义了一个synchronized的static函数A,也定义了一个synchronized 的instance函数B,那么这个类的同一对象Obj在多线程中分别访问A和B两个方法时,不会构成同步,因为它们的锁都不一样。A方法的锁是Obj这个对象,而B的锁是Obj所属的那个Class。

 

小结如下:

搞清楚synchronized锁定的是哪个对象,就能帮助我们设计更安全的多线程程序。


 

还有一些技巧可以让我们对共享资源的同步访问更加安全:

1.  定义private 的instance变量+它的 get方法,而不要定义public/protected的instance变量。如果将变量定义为public,对象在外界可以绕过同步方法的控制而直接取得它,并改动它。这也是JavaBean的标准实现方式之一。

2.  如果instance变量是一个对象,如数组或ArrayList什么的,那上述方法仍然不安全,因为当外界对象通过get方法拿到这个instance对象的引用后,又将其指向另一个对象,那么这个private变量也就变了,岂不是很危险。 这个时候就需要将get方法也加上synchronized同步,并且,只返回这个private对象的clone()――这样,调用端得到的就是对象副本的引用了。

<think>好的,我现在需要回答用户关于Javasynchronized关键字的作用用法的问题。用户已经提供了之前的对话历史一些引用资料,我需要综合这些信息来给出一个结构清晰、内容详实的回答。 首先,回顾用户的问题,用户明确想了解synchronized作用用法。根据之前的回答,用户可能已经对多线程同步有一定的了解,特别是在Android OpenGL开发中的使用场景。现在需要更一般性地解释synchronized,并结合提供的引用资料来加强回答的准确性。 接下来,我需要确定回答的结构。用户之前的回答分为几个部分,如问题分析、解决方案示例、关键点分析、常见问题与解决方案、优化建议等。但这次的问题更基础,可能更适合分点讲解作用用法,再结合示例注意事项。 首先,synchronized作用。根据引用资料,主要作用是控制多线程并发访问共享资源,确保线程安全,防止数据不一致。需要强调其作为内置锁的机制,保证原子性、可见性有序性。引用[3][4]都提到了这一点,需要引用这些内容来支持。 然后是使用方法。根据引用[1],synchronized有三种应用方式:实例方法同步、静态方法同步、代码块同步。需要详细解释这三种方式,并给出代码示例。例如,实例方法使用synchronized修饰,静态方法使用synchronized修饰,代码块则指定锁对象。引用[4]也提到了这些方法,可以引用说明。 需要注意的要点包括锁对象的选择、锁的粒度、死锁风险以及性能影响。例如,使用不同的锁对象会影响同步的范围,过粗的锁粒度可能导致性能问题。引用[2]提到了性能问题死锁风险,需要指出这些注意事项。 另外,用户之前的回答提到了使用ReentrantLock读写锁作为优化建议,这里是否需要提及?可能作为高级用法或替代方案简要说明,但用户当前问题集中在synchronized本身,所以可能放在注意事项或扩展部分。 接下来考虑代码示例。需要展示三种使用方式的代码,例如同步实例方法同步静态方法同步代码块。确保示例简洁易懂,符合用户提供的代码格式(如之前的Java示例)。 在注意事项部分,需要强调正确选择锁对象,避免锁粒度过大或过小,以及死锁的预防。引用[2][3]提到的性能问题死锁风险可以作为支持。 最后,是否需要比较synchronized其他同步机制,如ReentrantLock?可能作为扩展内容,但用户的问题主要关注synchronized,所以可能放在相关问题里,或者简要提及。 现在需要检查引用资料,确保正确引用。例如,引用[1]提到三种应用方式,引用[3][4]说明作用,引用[2]讨论注意事项。在回答中适当添加引用标识,如[^1][^3][^4]。 最后,生成相关问题,考虑用户可能想深入了解的内容,如与其他锁的比较、性能优化、实际应用中的问题等。 总结结构: 1. 作用(线程安全、原子性、可见性、有序性) 2. 三种使用方法(实例方法、静态方法、代码块),附代码示例 3. 注意事项(锁对象、粒度、死锁、性能) 4. 扩展建议(高级同步机制) 5. 相关问题 需要确保语言简洁,逻辑清晰,符合中文表达,正确使用LaTeX格式,如变量用$...$,独立公式用$$...$$,但可能在这部分内容中数学公式较少,主要代码示例。</think>### Java `synchronized` 关键字的作用使用方法详解 #### 一、核心作用 `<span style="color:green">synchronized`</span> 是 Java 中实现线程同步的核心关键字,主要用于解决多线程环境下的共享资源竞争问题,确保 **线程安全性**。其核心作用包括: 1. **原子性**:保证同一时刻只有一个线程执行同步代码块或方法[^4] - 例如:多个线程对共享变量 `$count$` 的 `$++$` 操作需原子化 2. **可见性**:确保线程对共享变量的修改对其他线程立即可见(基于 JMM 的锁释放-获取规则)[^3] 3. **有序性**:禁止编译器处理器对同步代码块内的指令重排序[^2] #### 二、三种基础用法与示例 根据引用[1][^1],`synchronized` 的用法分为以下三类: ##### 1. **同步实例方法** ```java public class Counter { private int count = 0; // 锁对象为当前实例(this) public synchronized void increment() { count++; } } ``` - **适用场景**:多个线程操作同一个对象实例的共享资源 - **锁对象**:当前实例(`this`) ##### 2. **同步静态方法** ```java public class Logger { private static int logCount = 0; // 锁对象为类的Class对象(Logger.class) public static synchronized void log(String message) { logCount++; System.out.println(message); } } ``` - **适用场景**:静态资源共享(如全局计数器) - **锁对象**:类的 `Class` 对象(如 `Logger.class`) ##### 3. **同步代码块** ```java public class ResourcePool { private final Object lock = new Object(); // 专用锁对象 private List<Resource> pool = new ArrayList<>(); public void addResource(Resource res) { synchronized(lock) { // 显式指定锁对象 pool.add(res); } } } ``` - **适用场景**:需要更细粒度的锁控制 - **锁对象**:任意非空对象(推荐使用专用锁对象) #### 三、关键注意事项 1. **锁对象选择** - 实例方法锁:`this` - 静态方法锁:`ClassName.class` - 代码块锁:自定义对象(避免与外部锁冲突) - *错误示例*:使用字符串常量或基本类型包装类(可能引发意外锁竞争)[^3] 2. **锁粒度控制** - **粗粒度锁**:同步整个方法,简单但并发性差 ```java public synchronized void processData() { /* 耗时操作 */ } ``` - **细粒度锁**:仅同步关键代码段,提升并发性能 ```java public void processData() { // 非同步操作... synchronized(lock) { // 关键共享资源操作 } } ``` 3. **死锁风险防范** - 典型死锁场景: ```java // 线程A synchronized(obj1) { synchronized(obj2) { ... } } // 线程B synchronized(obj2) { synchronized(obj1) { ... } } ``` - 解决方案:统一锁获取顺序、使用 `tryLock` 超时机制(需配合 `ReentrantLock`)[^2] 4. **性能影响** - 同步代码执行时间越长,线程阻塞概率越高 - 优化策略: - 减少同步代码块范围(如避免在同步块内执行 I/O 操作) - 对读多写少场景使用读写锁(`ReadWriteLock`) #### 四、扩展:高级同步机制对比 | 机制 | 特点 | 适用场景 | |---------------------|----------------------------------------------------------------------|------------------------------| | `synchronized` | 内置锁、自动释放、不可中断 | 简单的同步需求 | | `ReentrantLock` | 可重入、支持公平锁、可中断、超时尝试 | 复杂锁控制(如死锁恢复)[^2] | | `ReadWriteLock` | 读写分离,允许多个读线程同时访问 | 读多写少场景 | | `StampedLock` (Java8)| 乐观读锁、支持锁升级 | 高并发读场景 | #### 五、典型代码示例 ```java // 银行账户转账的线程安全实现 public class BankAccount { private double balance; private final Object lock = new Object(); // 存款(同步方法) public synchronized void deposit(double amount) { balance += amount; } // 转账(同步代码块) public void transfer(BankAccount target, double amount) { synchronized(BankAccount.class) { // 锁定所有账户的类级别操作 synchronized(this) { synchronized(target) { this.balance -= amount; target.balance += amount; } } } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值