java的同步实现

在java编程中,经常需要用到同步,而同步的实现使用最多的就是synchronized关键字了。

synchronized关键字涉及到“锁”的概念,首先先了解一下相关锁的知识。

java的内置锁:每个java对象都可以用做一个实现同步的锁,这些锁成为内置锁。线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁。获得内置锁的唯一途径就是进入这个锁的保护的同步代码块或方法。

java内置锁是一个互斥锁,这就是意味着最多只有一个线程能够获得该锁,当线程A尝试去获得线程B持有的内置锁时,线程A必须等待或者阻塞,直到线程B释放这个锁,如果B线程不释放这个锁,那么A线程将永远等待下去。

java中的锁按级别可分为:对象锁或方法锁,类锁这两种。

java的对象锁(或方法锁)和类锁在锁的概念上与内置锁基本一致,但对象锁和类锁之间是有很大区别的。

区别:1、对象锁用于对象实例方法,类锁是用于类的静态方法或者一个类的class对象上。

     2、类的对象可以有多个,所以不同的对象实例可以有多个对象锁,且互不干扰。每个类只有一个class对象,所以每个类只有一个类锁。

synchronized的用法:synchronized修改方法或者synchronized修饰代码块。

下面通过具体实例分析两种用法在对象锁和类锁上区别:

对象锁的synchronized修饰方法和代码块:

public class TestSynchronizedForObjectLock {

    public void test1(){
        synchronized(this){
            int i=5;
            while(i-- > 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

    public synchronized void test2(){
        int i =5;
        while(i-- > 0){
            System.out.println(Thread.currentThread().getName() + ":" + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        TestSynchronizedForObjectLock t = new TestSynchronizedForObjectLock();
        Thread t1 = new Thread(new Runnable(){public void run(){t.test1();}},"test1");
        Thread t2 = new Thread(new Runnable(){public void run(){t.test2();}},"test2");

        t1.start();
        t2.start();
    }

}

其运行结果:

test1:4
test1:3
test1:2
test1:1
test1:0
test2:4
test2:3
test2:2
test2:1
test2:0

上述的代码,第一个方法时用了同步代码块的方式进行同步,传入的对象实例是this,表明是当前对象;第二个方法是修饰方法的方式进行同步。因为第一个同步代码块传入的this,所以两个同步代码所需要获得的对象锁都是同一个对象锁,下面main方法时分别开启两个线程,分别调用test1和test2方法,那么两个线程都需要获得该对象锁,另一个线程必须等待。上面也给出了运行的结果可以看到:直到test1线程执行完毕,释放掉锁,test2线程才开始执行。

如果我们把test2方法的synchronized关键字去掉,执行结果会如何呢?运行结果:

test1:4
test2:4
test2:3
test1:3
test2:2
test1:2
test2:1
test1:1
test2:0
test1:0

上面是执行结果,我们可以看到,结果输出是交替着进行输出的,这是因为,某个线程得到了对象锁,但是另一个线程还是可以访问没有进行同步的方法或者代码。进行了同步的方法(加锁方法)和没有进行同步的方法(普通方法)是互不影响的,一个线程进入了同步方法,得到了对象锁,其他线程还是可以访问那些没有同步的方法(普通方法)。

所以synchronized只是一个内置锁的加锁机制,当某个方法加上synchronized关键字后,就表明要获得该内置锁才能执行,并不能阻止其他线程访问不需要获得该内置锁的方法。

类锁的synchronized修饰方法和代码块:

public class TestSynchronizedForClassLock {

    public void test3(){

        synchronized(this.getClass()){
            int i=5;
            while(i-- > 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

    public static synchronized void test4(){
        int i=5;
        while(i-- > 0){
            System.out.println(Thread.currentThread().getName() + ":" + i);

            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        TestSynchronizedForClassLock c = new TestSynchronizedForClassLock();
        Thread t3 = new Thread(new Runnable(){public void run(){c.test3();}});
        Thread t4 = new Thread(new Runnable(){public void run(){TestSynchronizedForClassLock.test4();}});

        t3.start();
        t4.start();

    }
}

运行结果:

Thread-0:4
Thread-0:3
Thread-0:2
Thread-0:1
Thread-0:0
Thread-1:4
Thread-1:3
Thread-1:2
Thread-1:1
Thread-1:0

其实,类锁修饰方法和代码块的效果和对象锁是一样的,因为类锁只是一个抽象出来的概念,只是为了区别静态方法的特点,因为静态方法是所有对象实例共用的,所以对应着synchronized修饰的静态方法的锁也是唯一的,所以抽象出来个类锁。其实这里的重点在下面这块代码,synchronized同时修饰静态和非静态方法:

public class TestSynchronizedForClassLock {

    public synchronized void test3(){

            int i=5;
            while(i-- > 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

    }

    public static synchronized void test4(){
        int i=5;
        while(i-- > 0){
            System.out.println(Thread.currentThread().getName() + ":" + i);

            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        TestSynchronizedForClassLock c = new TestSynchronizedForClassLock();
        Thread t3 = new Thread(new Runnable(){public void run(){c.test3();}});
        Thread t4 = new Thread(new Runnable(){public void run(){TestSynchronizedForClassLock.test4();}});

        t3.start();
        t4.start();

    }
}

运行结果:

Thread-0:4
Thread-1:4
Thread-0:3
Thread-1:3
Thread-0:2
Thread-1:2
Thread-0:1
Thread-1:1
Thread-1:0
Thread-0:0

上面代码synchronized同时修饰静态方法和实例方法,但是运行结果是交替进行的,这证明了类锁和对象锁是两个不一样的锁,控制着不同的区域,它们是互不干扰的。同样,线程获得对象锁的同时,也可以获得该类锁,即同时获得两个锁,这是允许的。

时间: 2024-11-08 01:33:02

java的同步实现的相关文章

Java 线程同步

Java 线程同步根本上是要符合一个逻辑:加锁------>修改------>释放锁 1.同步代码块 示例如下: public class SyncBlock { static class DataWrap { int i; } static class SyncBlockThread extends Thread { private DataWrap date; public SyncBlockThread(DataWrap dataWrap) { this.date = dataWrap;

java基础知识回顾之java Thread类学习(六)--java多线程同步函数用的锁

1.验证同步函数使用的锁----普通方法使用的锁 思路:创建两个线程,同时操作同一个资源,还是用卖票的例子来验证.创建好两个线程t1,t2,t1线程走同步代码块操作tickets,t2,线程走同步函数封装的代码操作tickets,同步代码块中的锁我们可以指定.假设我们事先不知道同步函数用的是什么锁:如果在同步代码块中指定的某个锁(测试)和同步函数用的锁相同,就不会出现线程安全问题,如果锁不相同,就会发生线程安全问题. 看下面的代码:t1线程用的同步锁是obj,t2线程在操作同步函数的资源,假设不

[Java][activiti]同步或者重构activiti identify用户数据的方法

同步或者重构Activiti Identify用户数据的多种方案比较 相信每个涉及到用户的系统都有一套用户权限管理平台或者模块,用来维护用户以及在系统内的功能.数据权限,我们使用的Activiti工作流引擎配套设计了包括User.Group的Identify模块,怎么和业务数据同步呢,这个问题是每个新人必问的问题之一,下面介绍几种同步方案,最后总结比较. 如果你在考虑直接使用Activiti引擎的Identify模块作为系统的用户数据管理模块,您真是奇才-开个玩笑 方案一:调用IdentifyS

(转) Java多线程同步与异步

Java线程 同步与异步 线程池1)多线程并发时,多个线程同时请求同一个资源,必然导致此资源的数据不安全,A线程修改了B线 程的处理的数据,而B线程又修改了A线程处理的数理.显然这是由于全局资源造成的,有时为了解 决此问题,优先考虑使用局部变量,退而求其次使用同步代码块,出于这样的安全考虑就必须牺牲 系统处理性能,加在多线程并发时资源挣夺最激烈的地方,这就实现了线程的同步机制 同步:A线程要请求某个资源,但是此资源正在被B线程使用中,因为同步机制存在,A线程请求 不到,怎么办,A线程只能等待下去

转:关于JAVA多线程同步

转:http://lanvis.blog.163.com/blog/static/26982162009798422547/ 因为需要,最近关注了一下JAVA多线程同步问题.JAVA多线程同步主要依赖于若干方法和关键字.将心得记录如下: 1  wait方法:        该方法属于Object的方法,wait方法的作用是使得当前调用wait方法所在部分(代码块)的线程停止执行,并释放当前获得的调用wait所在的代码块的锁,并在其他线程调用notify或者notifyAll方法时恢复到竞争锁状态

一篇搞定RSA加密与SHA签名|与Java完全同步

看到这篇文章的同学可幸福了,当时在做RSA加密与签名的时候网上的资料简直不要太老,做完后实在是忍受不下去了,这篇文章我会详细讲解iOS如何实现RSA加密与签名,并且与Java完全同步,这是我的第二篇博客,若有什么不足之处还请大家指教. 基础知识 什么是RSA? 答:RSA是一种非对称加密算法,常用来对传输数据进行加密,配合上数字摘要算法,也可以进行文字签名. RSA加密中padding? 答:padding即填充方式,由于RSA加密算法中要加密的明文是要比模数小的,padding就是通过一些填充

Java入门——同步与死锁

Java入门——同步与死锁 同步 解决资源共享的同步操作,可以使用同步代码块和同步方法两种方法完成. 1 package Sep19; 2 3 class MyThread implements Runnable{ 4 private int ticket=5; 5 public void run(){//覆写run方法 6 for(int i=0;i<100;i++){ 7 if (ticket>0){ 8 try{ 9 Thread.sleep(3000); 10 }catch(Inter

java中同步嵌套引起的死锁事例代码

/* 目的:自己写一个由于同步嵌套引起的死锁! 思路:多个线程在执行时,某一时刻,0-Thread绑定了LockA锁,1-Thread绑定了LockB锁! 当0-Thread要去绑定LockB锁时 和 1-Thread要去绑定LockA锁时都不能绑定,此时两个线程不能继续进行! */ class Ticket implements Runnable{ public boolean flag; Ticket(boolean flag){ this.flag = flag; } Ticket(){

java多线程-同步块

Java 同步块(synchronized block)用来标记方法或者代码块是同步的.Java 同步块用来避免竞争.本文介绍以下内容: Java 同步关键字(synchronzied) 实例方法同步 静态方法同步 实例方法中同步块 静态方法中同步块 Java 同步示例 Java 同步关键字(synchronized) Java 中的同步块用 synchronized 标记.同步块在 Java 中是同步在某个对象上.所有同步在一个对象上的同步块在同时只能被一个线程进入并执行操作.所有其他等待进入

java线程 同步临界区:thinking in java4 21.3.5

thinking in java 4免费下载:http://download.csdn.net/detail/liangrui1988/7580155 package org.rui.thread.critical; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutorService; import java.uti