精华内容
下载资源
问答
  • JAVA线程之——对象锁的理解

    千次阅读 2018-07-28 14:24:24
    athread.start()后,调用addI(),传入字符”a”,”a set over”后,线程a睡眠了,并未释放a的,bthread.start()后,可以调用addI,因为他们不是一个HasSelfPrivateNum对象也不是一个,输出”b set over”,。...

    转载自微信公众号 Java面试通关手册 ——Java多线程学习(二)synchronized关键字(1)作者:Snaiclimb

    多个对象多个锁

    例子:

    这里写图片描述
    这里写图片描述
    这里写图片描述
    这里写图片描述

    输出
    这里写图片描述

    代码解释:
    athread.start()后,调用addI(),传入字符”a”,”a set over”后,线程a睡眠了,并未释放a的锁,bthread.start()后,可以调用addI,因为他们不是一个HasSelfPrivateNum对象,锁也不是一个锁,输出”b set over”,。。。然后a醒来继续输出。。。

    synchronized取得的锁都是对象锁,而不是把一段代码或方法当做锁。如果多个线程访问的是同一个对象,哪个线程先执行带synchronized关键字的方法,则哪个线程就持有该方法,那么其他线程只能呈等待状态。如果多个线程访问的是多个对象则不一定,因为多个对象会产生多个锁。

    那么我们思考一下当多个线程访问的是同一个对象中的非synchronized类型方法会是什么效果?重点内容

    答案是:会异步调用非synchronized类型方法,解决办法也很简单在非synchronized类型方法前加上synchronized关键字即可。

    脏读

    发生脏读的情况实在读取实例变量时,此值已经被其他线程更改过。
    代码
    这里写图片描述

    这里写图片描述
    这里写图片描述
    输出:
    这里写图片描述

    代码解释:
    thread.start(),会调用setValue(“B”,”BB”)
    username赋值为B,然后线程睡眠,资源交给主线程main(),主线程也睡眠,但是时间短,于是主线程先开始执行下面的语句,即g调用了getValue,此时由于thread处于休眠,只赋值了username,所以getValue是 B AA,待thread唤醒后,继续赋值,输出B BB ,问题就在于,setValue还未执行完毕的时候,主线程就访问了getValue导致了脏读,加入synchronized之后,由于锁是对象锁,即使thread在睡眠,但是并未释放对象锁,所以主线程main此时并不可以访问有sychronized的getValue!

    问题:如果线程都不休眠,那么thread和main线程是同时运行吗,同时的话就也有可能产生和上面情况相似的脏读,涉及到多线程的本质问题,多线程是怎么运行的,同时吗?
    解释:并发与并行
    这里写图片描述

    • 微观角度:所有的并发处理都有排队等候,唤醒,执行等这样的步骤,在微观上他们都是序列被处理的,如果是同一时刻到达的请求(或线程)也会根据优先级的不同,而先后进入队列排队等候执行。
    • 宏观角度:多个几乎同时到达的请求(或线程)在宏观上看就像是同时在被处理。
    • 通俗点讲,并发就是只有一个CPU资源,程序(或线程)之间要竞争得到执行机会。图中的第一个阶段,在A执行的过程中B,C不会执行,因为这段时间内这个CPU资源被A竞争到了,同理,第二个阶段只有B在执行,第三个阶段只有C在执行。其实,并发过程中,A,B,C并不是同时在进行的(微观角度)。但又是同时进行的(宏观角度)。

    getvalue()加上synchronized
    这里写图片描述

    展开全文
  • 最近工作有用到一些多线程的东西,之前吧,有用到synchronized同步块,不过是别人怎么用就跟着用,并没有搞清楚的概念。最近也是遇到一些问题,不搞清楚的概念,很容易碰壁,甚至有些时候自己连用没用对都不知道...

    最近工作有用到一些多线程的东西,之前吧,有用到synchronized同步块,不过是别人怎么用就跟着用,并没有搞清楚锁的概念。最近也是遇到一些问题,不搞清楚锁的概念,很容易碰壁,甚至有些时候自己连用没用对都不知道。

    今天把一些疑惑都解开了,写篇文章分享给大家,文章还算比较全面。当然可能有小宝鸽理解得不够深入透彻的地方,如果说得不正确还望指出。

    看之前有必要跟某些猿友说一下,如果看一遍没有看明白呢,也没关系,当是了解一下,等真正使用到了,再回头看。

    本文主要是将synchronized关键字用法作为例子来去解释Java中的对象锁和类锁。特别的是希望能帮大家理清一些概念。

    一、synchronized关键字

    synchronized关键字有如下两种用法:

    1、 在需要同步的方法的方法签名中加入synchronized关键字。

    synchronized public void getValue() {
        System.out.println("getValue method thread name="
                + Thread.currentThread().getName() + " username=" + username
                + " password=" + password);
    }

    上面的代码修饰的synchronized是非静态方法,如果修饰的是静态方法(static)含义是完全不一样的。具体不一样在哪里,后面会详细说清楚。

    synchronized static public void getValue() {
        System.out.println("getValue method thread name="
                + Thread.currentThread().getName() + " username=" + username
                + " password=" + password);
    }

    2、使用synchronized块对需要进行同步的代码段进行同步。

    public void serviceMethod() {
        try {
            synchronized (this) {
                System.out.println("begin time=" + System.currentTimeMillis());
                Thread.sleep(2000);
                System.out.println("end    end=" + System.currentTimeMillis());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    上面的代码块是synchronized (this)用法,还有synchronized (非this对象)以及synchronized (类.class)这两种用法,这些使用方式的含义也是有根本的区别的。我们先带着这些问题继续往下看。

    二、Java中的对象锁和类锁

    小宝鸽似乎并没有办法用清晰简短的语言来描述对象锁和类锁的概念。即便能用简单的语句概况,也会显得抽象。猿友们耐心看完自然会明白。

    之前网上有找一些相关资料,有篇博客是这样描述的(看的是转载的,原创连接我也不知道):

    一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,
    在Java里边就是拿到某个同步对象的锁(一个对象只有一把锁);
    如果这个时候同步对象的锁被其他线程拿走了,他(这个线程)就只能等了(线程阻塞在锁池等待队列中)。 
    取到锁后,他就开始执行同步代码(被synchronized修饰的代码);
    线程执行完同步代码后马上就把锁还给同步对象,其他在锁池中等待的某个线程就可以拿到锁执行同步代码了。
    这样就保证了同步代码在统一时刻只有一个线程在执行。

    上面提到锁,这里先引出锁的概念。先来看看下面这些啰嗦而必不可少的文字。

    多线程的线程同步机制实际上是靠锁的概念来控制的。

    在Java程序运行时环境中,JVM需要对两类线程共享的数据进行协调:
    1)保存在堆中的实例变量
    2)保存在方法区中的类变量

    这两类数据是被所有线程共享的。
    (程序不需要协调保存在Java 栈当中的数据。因为这些数据是属于拥有该栈的线程所私有的。)

    这里插播一下广告:关于JVM内存,如果想了解可以看看博主的另外一篇文章:

    Java内存管理:http://blog.csdn.net/u013142781/article/details/50830754

    方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的应该是与Java堆区分开来。

    :在Java中,JVM中的栈记录了线程的方法调用。每个线程拥有一个栈。在某个线程的运行过程中,如果有新的方法调用,那么该线程对应的栈就会增加一个存储单元,即帧(frame)。在frame中,保存有该方法调用的参数、局部变量和返回地址。

    是JVM中一块可自由分配给对象的区域。当我们谈论垃圾回收(garbage collection)时,我们主要回收堆(heap)的空间。
    Java的普通对象存活在堆中。与栈不同,堆的空间不会随着方法调用结束而清空。因此,在某个方法中创建的对象,可以在方法调用结束之后,继续存在于堆中。这带来的一个问题是,如果我们不断的创建新的对象,内存空间将最终消耗殆尽。

    在java虚拟机中,每个对象和类在逻辑上都是和一个监视器相关联的。
    对于对象来说,相关联的监视器保护对象的实例变量。

    对于类来说,监视器保护类的类变量。

    (如果一个对象没有实例变量,或者一个类没有变量,相关联的监视器就什么也不监视。)
    为了实现监视器的排他性监视能力,java虚拟机为每一个对象和类都关联一个锁。代表任何时候只允许一个线程拥有的特权。线程访问实例变量或者类变量不需锁。

    但是如果线程获取了锁,那么在它释放这个锁之前,就没有其他线程可以获取同样数据的锁了。(锁住一个对象就是获取对象相关联的监视器)

    类锁实际上用对象锁来实现。当虚拟机装载一个class文件的时候,它就会创建一个java.lang.Class类的实例。当锁住一个对象的时候,实际上锁住的是那个类的Class对象。

    一个线程可以多次对同一个对象上锁。对于每一个对象,java虚拟机维护一个加锁计数器,线程每获得一次该对象,计数器就加1,每释放一次,计数器就减 1,当计数器值为0时,锁就被完全释放了。

    java编程人员不需要自己动手加锁,对象锁是java虚拟机内部使用的。

    在java程序中,只需要使用synchronized块或者synchronized方法就可以标志一个监视区域。当每次进入一个监视区域时,java 虚拟机都会自动锁上对象或者类。

    三、synchronized关键字各种用法与实例

    看完了”二、Java中的对象锁和类锁”,我们再来结合”一、synchronized关键字”里面提到的synchronized用法。

    事实上,synchronized修饰非静态方法、同步代码块的synchronized (this)用法和synchronized (非this对象)的用法锁的是对象,线程想要执行对应同步代码,需要获得对象锁。

    synchronized修饰静态方法以及同步代码块的synchronized (类.class)用法锁的是类,线程想要执行对应同步代码,需要获得类锁。

    因此,事实上synchronized关键字可以细分为上面描述的五种用法。

    本文的实例均来自于《Java多线程编程核心技术》这本书里面的例子。

    1、我们先看看非线程安全实例(Run.java):

    public class Run {
    
        public static void main(String[] args) {
    
            HasSelfPrivateNum numRef = new HasSelfPrivateNum();
    
            ThreadA athread = new ThreadA(numRef);
            athread.start();
    
            ThreadB bthread = new ThreadB(numRef);
            bthread.start();
    
        }
    
    }
    
    class HasSelfPrivateNum {
    
        private int num = 0;
    
        public void addI(String username) {
            try {
                if (username.equals("a")) {
                    num = 100;
                    System.out.println("a set over!");
                    Thread.sleep(2000);
                } else {
                    num = 200;
                    System.out.println("b set over!");
                }
                System.out.println(username + " num=" + num);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    
    }
    
    
    class ThreadA extends Thread {
    
        private HasSelfPrivateNum numRef;
    
        public ThreadA(HasSelfPrivateNum numRef) {
            super();
            this.numRef = numRef;
        }
    
        @Override
        public void run() {
            super.run();
            numRef.addI("a");
        }
    
    }
    
    
    
     class ThreadB extends Thread {
    
        private HasSelfPrivateNum numRef;
    
        public ThreadB(HasSelfPrivateNum numRef) {
            super();
            this.numRef = numRef;
        }
    
        @Override
        public void run() {
            super.run();
            numRef.addI("b");
        }
    
    }

    运行结果为:

    a set over!
    b set over!
    b num=200
    a num=200

    修改HasSelfPrivateNum如下,方法用synchronized修饰如下:

    class HasSelfPrivateNum {
    
        private int num = 0;
    
        synchronized public void addI(String username) {
            try {
                if (username.equals("a")) {
                    num = 100;
                    System.out.println("a set over!");
                    Thread.sleep(2000);
                } else {
                    num = 200;
                    System.out.println("b set over!");
                }
                System.out.println(username + " num=" + num);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    
    }

    运行结果是线程安全的:

    b set over!
    b num=200
    a set over!
    a num=100

    实验结论:两个线程访问同一个对象中的同步方法是一定是线程安全的。本实现由于是同步访问,所以先打印出a,然后打印出b

    这里线程获取的是HasSelfPrivateNum的对象实例的锁——对象锁。

    2、多个对象多个锁

    就上面的实例,我们将Run改成如下:

    public class Run {
    
        public static void main(String[] args) {
    
            HasSelfPrivateNum numRef1 = new HasSelfPrivateNum();
            HasSelfPrivateNum numRef2 = new HasSelfPrivateNum();
    
            ThreadA athread = new ThreadA(numRef1);
            athread.start();
    
            ThreadB bthread = new ThreadB(numRef2);
            bthread.start();
    
        }
    
    }

    运行结果为:

    a set over!
    b set over!
    b num=200
    a num=200

    这里是非同步的,因为线程athread获得是numRef1的对象锁,而bthread线程获取的是numRef2的对象锁,他们并没有在获取锁上有竞争关系,因此,出现非同步的结果

    这里插播一下:同步不具有继承性

    3、同步块synchronized (this)

    我们先看看代码实例(Run.java)

    public class Run {
    
        public static void main(String[] args) {
            ObjectService service = new ObjectService();
    
            ThreadA a = new ThreadA(service);
            a.setName("a");
            a.start();
    
            ThreadB b = new ThreadB(service);
            b.setName("b");
            b.start();
        }
    
    }
    
    class ObjectService {
    
        public void serviceMethod() {
            try {
                synchronized (this) {
                    System.out.println("begin time=" + System.currentTimeMillis());
                    Thread.sleep(2000);
                    System.out.println("end    end=" + System.currentTimeMillis());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    
    class ThreadA extends Thread {
    
        private ObjectService service;
    
        public ThreadA(ObjectService service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            super.run();
            service.serviceMethod();
        }
    
    }
    
    
    class ThreadB extends Thread {
        private ObjectService service;
    
        public ThreadB(ObjectService service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            super.run();
            service.serviceMethod();
        }
    }

    运行结果:

    begin time=1466148260341
    end    end=1466148262342
    begin time=1466148262342
    end    end=1466148264378
    

    这样也是同步的,线程获取的是同步块synchronized (this)括号()里面的对象实例的对象锁,这里就是ObjectService实例对象的对象锁了。

    需要注意的是synchronized (){}的{}前后的代码依旧是异步的

    4、synchronized (非this对象)

    我们先看看代码实例(Run.java)

    public class Run {
    
        public static void main(String[] args) {
    
            Service service = new Service("xiaobaoge");
    
            ThreadA a = new ThreadA(service);
            a.setName("A");
            a.start();
    
            ThreadB b = new ThreadB(service);
            b.setName("B");
            b.start();
    
        }
    
    }
    
    class Service {
    
        String anyString = new String();
    
        public Service(String anyString){
            this.anyString = anyString;
        }
    
        public void setUsernamePassword(String username, String password) {
            try {
                synchronized (anyString) {
                    System.out.println("线程名称为:" + Thread.currentThread().getName()
                            + "在" + System.currentTimeMillis() + "进入同步块");
                    Thread.sleep(3000);
                    System.out.println("线程名称为:" + Thread.currentThread().getName()
                            + "在" + System.currentTimeMillis() + "离开同步块");
                }
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    
    }
    
    class ThreadA extends Thread {
        private Service service;
    
        public ThreadA(Service service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            service.setUsernamePassword("a", "aa");
    
        }
    
    }
    
    
    class ThreadB extends Thread {
    
        private Service service;
    
        public ThreadB(Service service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            service.setUsernamePassword("b", "bb");
    
        }
    
    }

    不难看出,这里线程争夺的是anyString的对象锁,两个线程有竞争同一对象锁的关系,出现同步

    现在有一个问题:一个类里面有两个非静态同步方法,会有影响么?

    答案是:如果对象实例A,线程1获得了对象A的对象锁,那么其他线程就不能进入需要获得对象实例A的对象锁才能访问的同步代码(包括同步方法和同步块)。不理解可以细细品味一下!

    5、静态synchronized同步方法

    我们直接看代码实例:

    public class Run {
    
        public static void main(String[] args) {
    
            ThreadA a = new ThreadA();
            a.setName("A");
            a.start();
    
            ThreadB b = new ThreadB();
            b.setName("B");
            b.start();
    
        }
    
    }
    
    class Service {
    
        synchronized public static void printA() {
            try {
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "进入printA");
                Thread.sleep(3000);
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "离开printA");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        synchronized public static void printB() {
            System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
                    + System.currentTimeMillis() + "进入printB");
            System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
                    + System.currentTimeMillis() + "离开printB");
        }
    
    }
    
    
    class ThreadA extends Thread {
        @Override
        public void run() {
            Service.printA();
        }
    
    }
    
    
    class ThreadB extends Thread {
        @Override
        public void run() {
            Service.printB();
        }
    }

    运行结果:

    线程名称为:A1466149372909进入printA
    线程名称为:A1466149375920离开printA
    线程名称为:B在1466149375920进入printB
    线程名称为:B在1466149375920离开printB

    两个线程在争夺同一个类锁,因此同步

    6、synchronized (class)

    对上面Service类代码修改成如下:

    class Service {
    
        public static void printA() {
            synchronized (Service.class) {
                try {
                    System.out.println("线程名称为:" + Thread.currentThread().getName()
                            + "在" + System.currentTimeMillis() + "进入printA");
                    Thread.sleep(3000);
                    System.out.println("线程名称为:" + Thread.currentThread().getName()
                            + "在" + System.currentTimeMillis() + "离开printA");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
        }
    
        public static void printB() {
            synchronized (Service.class) {
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "进入printB");
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "离开printB");
            }
        }
    }
    

    运行结果:

    线程名称为:A1466149372909进入printA
    线程名称为:A1466149375920离开printA
    线程名称为:B在1466149375920进入printB
    线程名称为:B在1466149375920离开printB

    两个线程依旧在争夺同一个类锁,因此同步

    需要特别说明:对于同一个类A,线程1争夺A对象实例的对象锁,线程2争夺类A的类锁,这两者不存在竞争关系。也就说对象锁和类锁互补干预内政

    静态方法则一定会同步,非静态方法需在单例模式才生效,但是也不能都用静态同步方法,总之用得不好可能会给性能带来极大的影响。另外,有必要说一下的是Spring的bean默认是单例的。

    展开全文
  • Java线程全局对象锁

    千次阅读 2018-05-12 17:49:04
      我们看一个例子: class Demo { public synchronized void test() { ...test方法开始执行,当前线程为:"+Thread.currentThread().getName()); try { Thread.sleep(1000); ...

      我们看一个例子:

    class Demo {
        public synchronized void test() {
            System.out.println("test方法开始执行,当前线程为:"+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println("test方法执行完毕,当前线程为:"+Thread.currentThread().getName());
        }
    }
    
    
    class MyThread implements Runnable {
    
        @Override
        public void run() {
            Demo demo = new Demo();
            demo.test();
        }
    
    }
    public class Test {
        public static void main(String[] args) {
            MyThread myThread = new MyThread();
            new Thread(myThread,"子线程A").start();
            new Thread(myThread,"子线程B").start();
            new Thread(myThread,"子线程C").start();
        }
    }

      运行结果:

    运行结果

      从运行结果我们可以看出,Demo类提供的test同步方法好像并没有起作用,这是怎么一回事。

      实际上,synchronized(this) 以及非 static 的 synchronized 方法,只能防止多个线程同时执行同一个对象的同步代码块。即 synchronized 锁住的是括号里的对象,而不是代码块

      所以说 synchronized 是一个对象锁。

      当 synchronized 锁住一个对象后,别的线程如果也想拿到这个对象的锁,就必须等待这个线程执行完成释放锁,才能再次给对象加锁,这样才能达到线程同步的目的。所以即使两个不同的代码块都要锁住同一个对象,那么这两个代码段也不能在多线程环境下同时运行,必须等其中一个现将对象锁释放掉,另一个才能给对象上锁。

      所以在上例中,MyThread线程类启动三次也创建了三个Demo类,并且对其调用,三个不同的对象进入了同步方法中,所以显示如上结果。

      当一个线程A 进入到同步方法所在的类中,其他线程不能进入该类中的其他类中,因为锁住的是对象。类比:厕所里有个电视机,某人上厕所时关上了锁,其他人也不能进来看电视。

      那我们如果想将一段代码锁住,使同时有且只有一个对象能访问该代码块应该如何操作。

      这种锁住代码块的的操作叫做全局锁,可以通过以下两种途径实现:

    1.1 锁住同一个对象

    class Demo {
        public void test() {
            // 锁住进入的方法的对象
            synchronized(this) {
                System.out.println("test方法开始执行,当前线程为:"+Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println("test方法执行完毕,当前线程为:"+Thread.currentThread().getName());
            }
        }
    }
    
    
    class MyThread implements Runnable {
        // 为了防止多个线程创建多个对象,所以在类中自己创建一个对象
        private Demo demo;
        // 在构造方MyThread时将真正的对象传入
        public MyThread(Demo demo) {
            this.demo = demo;
        }
    
        @Override
        public void run() {
            this.demo.test();
        }
    
    }
    public class Test {
        public static void main(String[] args) {
            // 实际上,整个程序只有这一个对象
            // 锁住了该对象就相当于将 Demo类中的test方法代码锁住了,曲线救国实现全局锁
            Demo demo = new Demo();
            MyThread myThread = new MyThread(demo);
            new Thread(myThread,"子线程A").start();
            new Thread(myThread,"子线程B").start();
            new Thread(myThread,"子线程C").start();
        }
    }

    1.2 锁住整个类

    class Demo {
        public void test() {
            // 将 Demo类 作为锁定的对象,每次只能有一个对象进入该类
            synchronized(Demo.class) {
                System.out.println("test方法开始执行,当前线程为:"+Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println("test方法执行完毕,当前线程为:"+Thread.currentThread().getName());
            }
        }
    }
    
    
    class MyThread implements Runnable {
    
        @Override
        public void run() {
            // 虽然这里还是存在创建多个对象的问题
            // 但是由于test方法这次锁住了整个类,所以同时有且仅有一个对象能够进入Demo类中
            Demo demo = new Demo();
            demo.test();
        }
    
    }
    public class Test {
        public static void main(String[] args) {
            MyThread myThread = new MyThread();
            new Thread(myThread,"子线程A").start();
            new Thread(myThread,"子线程B").start();
            new Thread(myThread,"子线程C").start();
        }
    }

      运行结果:

    运行结果

      当然,使用静态同步方法也可以实现锁住整个类的效果。

    public static synchronized test() {
        // statement
    }
    展开全文
  • 本文主要是将synchronized关键字用法作为例子来去解释Java中的对象锁 和 类。一、synchronized关键字synchronized关键字有如下两种用法:1、 在需要同步的方法的方法签名中加入synchronized关键字。synchronized ...

    本文主要是将synchronized关键字用法作为例子来去解释Java中的对象锁 和 类锁。

    对于同步,要时刻清醒在 哪个锁对象 上同步,这是关键。
    对于同步代码块,要看清楚什么对象已经用于锁定(synchronized后面括号的内容)。在同一个对象上进行同步的线程将彼此阻塞,在不同对象上锁定的线程将永远不会彼此阻塞。

    一、synchronized关键字

    synchronized关键字有如下两种用法:

    1、 在需要同步的方法的方法签名中加入synchronized关键字。

    synchronized public void getValue() {
        System.out.println("getValue method thread name="
                + Thread.currentThread().getName() + " username=" + username
                + " password=" + password);
    }

    上面的代码修饰的synchronized是非静态方法,如果修饰的是静态方法(static)含义是完全不一样的。具体不一样在哪里,后面会详细说清楚。

    synchronized static public void getValue() {
        System.out.println("getValue method thread name="
                + Thread.currentThread().getName() + " username=" + username
                + " password=" + password);
    }

    2、使用synchronized块对需要进行同步的代码段进行同步。

    public void serviceMethod() {
        try {
            synchronized (this) {
                System.out.println("begin time=" + System.currentTimeMillis());
                Thread.sleep(2000);
                System.out.println("end    end=" + System.currentTimeMillis());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    上面的代码块是synchronized (this)用法,还有synchronized (非this对象)以及synchronized (类.class)这两种用法,这些使用方式的含义也是有根本的区别的。我们先带着这些问题继续往下看。

    二、Java中的对象锁和类锁

    之前网上有找一些相关资料,有篇博客是这样描述的(看的是转载的,原创连接我也不知道):

    1.一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,
    2.在Java里边就是拿到某个同步对象的锁(一个对象只有一把锁);
    3.如果这个时候同步对象的锁被其他线程拿走了,他(这个线程)就只能等了(线程阻塞在锁池等待队列中)。 
    4.取到锁后,他就开始执行同步代码(被synchronized修饰的代码);
    5.线程执行完同步代码后马上就把锁还给同步对象,其他在锁池中等待的某个线程就可以拿到锁执行同步代码了。
    6.这样就保证了同步代码在同一时刻只有一个线程在执行。
    

    这段话,除了最后一句,讲得都是挺合理的。”这样就保证了同步代码在统一时刻只有一个线程在执行。”这句话显然不对,synchronized并非保证同步代码同一时刻只有一个线程执行,同步代码同一时刻应该可以有多个线程执行。

    上面提到锁,这里先引出锁的概念。先来看看下面这些啰嗦而必不可少的文字。

    多线程的线程同步机制实际上是靠锁的概念来控制的。

    在Java程序运行时环境中,JVM需要对两类线程共享的数据进行协调:
    1)保存在堆中的实例变量
    2)保存在方法区中的类变量

    这两类数据是被所有线程共享的。
    (程序不需要协调保存在Java 栈当中的数据。因为这些数据是属于拥有该栈的线程所私有的。)

    这里插播一下广告:关于JVM内存,如果想了解可以看看博主的另外一篇文章:

    Java内存管理:http://blog.csdn.net/u013142781/article/details/50830754

    方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的应该是与Java堆区分开来。

    :在Java中,JVM中的栈记录了线程的方法调用。每个线程拥有一个栈。在某个线程的运行过程中,如果有新的方法调用,那么该线程对应的栈就会增加一个存储单元,即帧(frame)。在frame中,保存有该方法调用的参数、局部变量和返回地址。

    是JVM中一块可自由分配给对象的区域。当我们谈论垃圾回收(garbage collection)时,我们主要回收堆(heap)的空间。
    Java的普通对象存活在堆中。与栈不同,堆的空间不会随着方法调用结束而清空。因此,在某个方法中创建的对象,可以在方法调用结束之后,继续存在于堆中。这带来的一个问题是,如果我们不断的创建新的对象,内存空间将最终消耗殆尽。

    在java虚拟机中,每个对象和类在逻辑上都是和一个监视器相关联的。
    对于对象来说,相关联的监视器保护对象的实例变量。

    对于类来说,监视器保护类的类变量。

    (如果一个对象没有实例变量,或者一个类没有变量,相关联的监视器就什么也不监视。)
    为了实现监视器的排他性监视能力,java虚拟机为每一个对象和类都关联一个锁。代表任何时候只允许一个线程拥有的特权。线程访问实例变量或者类变量不需锁。

    但是如果线程获取了锁,那么在它释放这个锁之前,就没有其他线程可以获取同样数据的锁了。(锁住一个对象就是获取对象相关联的监视器)

    类锁实际上用对象锁来实现。当虚拟机装载一个class文件的时候,它就会创建一个java.lang.Class类的实例。当锁住一个对象的时候,实际上锁住的是那个类的Class对象。

    一个线程可以多次对同一个对象上锁。对于每一个对象,java虚拟机维护一个加锁计数器,线程每获得一次该对象,计数器就加1,每释放一次,计数器就减 1,当计数器值为0时,锁就被完全释放了。

    java编程人员不需要自己动手加锁,对象锁是java虚拟机内部使用的。

    在java程序中,只需要使用synchronized块或者synchronized方法就可以标志一个监视区域。当每次进入一个监视区域时,java 虚拟机都会自动锁上对象或者类。

    三、synchronized关键字各种用法与实例

    看完了”二、Java中的对象锁和类锁”,我们再来结合”一、synchronized关键字”里面提到的synchronized用法。

    事实上,synchronized修饰非静态方法、同步代码块的synchronized (this)用法和synchronized (非this对象)的用法锁的是对象,线程想要执行对应同步代码,需要获得对象锁。

    synchronized修饰静态方法以及同步代码块的synchronized (类.class)用法锁的是类,线程想要执行对应同步代码,需要获得类锁。

    因此,事实上synchronized关键字可以细分为上面描述的五种用法。

    本文的实例均来自于《Java多线程编程核心技术》这本书里面的例子。

    1、我们先看看非线程安全实例(Run.java):

    public class Run {
    
        public static void main(String[] args) {
    
            HasSelfPrivateNum numRef = new HasSelfPrivateNum();
    
            ThreadA athread = new ThreadA(numRef);
            athread.start();
    
            ThreadB bthread = new ThreadB(numRef);
            bthread.start();
    
        }
    
    }
    
    class HasSelfPrivateNum {
    
        private int num = 0;
    
        public void addI(String username) {
            try {
                if (username.equals("a")) {
                    num = 100;
                    System.out.println("a set over!");
                    Thread.sleep(2000);
                } else {
                    num = 200;
                    System.out.println("b set over!");
                }
                System.out.println(username + " num=" + num);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    
    }
    
    
    class ThreadA extends Thread {
    
        private HasSelfPrivateNum numRef;
    
        public ThreadA(HasSelfPrivateNum numRef) {
            super();
            this.numRef = numRef;
        }
    
        @Override
        public void run() {
            super.run();
            numRef.addI("a");
        }
    
    }
    
    
    
     class ThreadB extends Thread {
    
        private HasSelfPrivateNum numRef;
    
        public ThreadB(HasSelfPrivateNum numRef) {
            super();
            this.numRef = numRef;
        }
    
        @Override
        public void run() {
            super.run();
            numRef.addI("b");
        }
    
    }

    运行结果为:

    a set over!
    b set over!
    b num=200
    a num=200

    修改HasSelfPrivateNum如下,方法用synchronized修饰如下:

    class HasSelfPrivateNum {
    
        private int num = 0;
    
        synchronized public void addI(String username) {
            try {
                if (username.equals("a")) {
                    num = 100;
                    System.out.println("a set over!");
                    Thread.sleep(2000);
                } else {
                    num = 200;
                    System.out.println("b set over!");
                }
                System.out.println(username + " num=" + num);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    
    }

    运行结果是线程安全的:

    b set over!
    b num=200
    a set over!
    a num=100

    实验结论:两个线程访问同一个对象中的同步方法是一定是线程安全的。本实现由于是同步访问,所以先打印出a,然后打印出b

    这里线程获取的是HasSelfPrivateNum的对象实例的锁——对象锁。

    2、多个对象多个锁

    就上面的实例,我们将Run改成如下:

    public class Run {
    
        public static void main(String[] args) {
    
            HasSelfPrivateNum numRef1 = new HasSelfPrivateNum();
            HasSelfPrivateNum numRef2 = new HasSelfPrivateNum();
    
            ThreadA athread = new ThreadA(numRef1);
            athread.start();
    
            ThreadB bthread = new ThreadB(numRef2);
            bthread.start();
    
        }
    
    }

    运行结果为:

    a set over!
    b set over!
    b num=200
    a num=100

    这里是非同步的,因为线程athread获得是numRef1的对象锁,而bthread线程获取的是numRef2的对象锁,他们并没有在获取锁上有竞争关系,因此,出现非同步的结果

    这里插播一下:同步不具有继承性

    3、同步块synchronized (this)

    我们先看看代码实例(Run.java)

    public class Run {
    
        public static void main(String[] args) {
            ObjectService service = new ObjectService();
    
            ThreadA a = new ThreadA(service);
            a.setName("a");
            a.start();
    
            ThreadB b = new ThreadB(service);
            b.setName("b");
            b.start();
        }
    
    }
    
    class ObjectService {
    
        public void serviceMethod() {
            try {
                synchronized (this) {
                    System.out.println("begin time=" + System.currentTimeMillis());
                    Thread.sleep(2000);
                    System.out.println("end    end=" + System.currentTimeMillis());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    
    class ThreadA extends Thread {
    
        private ObjectService service;
    
        public ThreadA(ObjectService service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            super.run();
            service.serviceMethod();
        }
    
    }
    
    
    class ThreadB extends Thread {
        private ObjectService service;
    
        public ThreadB(ObjectService service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            super.run();
            service.serviceMethod();
        }
    }

    运行结果:

    begin time=1466148260341
    end    end=1466148262342
    begin time=1466148262342
    end    end=1466148264378

    这样也是同步的,线程获取的是同步块synchronized (this)括号()里面的对象实例的对象锁,这里就是ObjectService实例对象的对象锁了。

    需要注意的是synchronized (){}的{}前后的代码依旧是异步的

    4、synchronized (非this对象)

    我们先看看代码实例(Run.java)

    public class Run {
    
        public static void main(String[] args) {
    
            Service service = new Service("xiaobaoge");
    
            ThreadA a = new ThreadA(service);
            a.setName("A");
            a.start();
    
            ThreadB b = new ThreadB(service);
            b.setName("B");
            b.start();
    
        }
    
    }
    
    class Service {
    
        String anyString = new String();
    
        public Service(String anyString){
            this.anyString = anyString;
        }
    
        public void setUsernamePassword(String username, String password) {
            try {
                synchronized (anyString) {
                    System.out.println("线程名称为:" + Thread.currentThread().getName()
                            + "在" + System.currentTimeMillis() + "进入同步块");
                    Thread.sleep(3000);
                    System.out.println("线程名称为:" + Thread.currentThread().getName()
                            + "在" + System.currentTimeMillis() + "离开同步块");
                }
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    
    }
    
    class ThreadA extends Thread {
        private Service service;
    
        public ThreadA(Service service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            service.setUsernamePassword("a", "aa");
    
        }
    
    }
    
    
    class ThreadB extends Thread {
    
        private Service service;
    
        public ThreadB(Service service) {
            super();
            this.service = service;
        }
    
        @Override
        public void run() {
            service.setUsernamePassword("b", "bb");
    
        }
    
    }

    不难看出,这里线程争夺的是anyString的对象锁,两个线程有竞争同一对象锁的关系,出现同步

    现在有一个问题:一个类里面有两个线程要访问 同一个 非静态同步方法,会有影响么?

    答案是:如果对象实例A,线程1获得了对象A的对象锁,那么其他线程就不能进入需要获得对象实例A的对象锁才能访问的同步代码(包括同步方法和同步块)。不理解可以细细品味一下!

    5、静态synchronized同步方法

    我们直接看代码实例:

    public class Run {
    
        public static void main(String[] args) {
    
            ThreadA a = new ThreadA();
            a.setName("A");
            a.start();
    
            ThreadB b = new ThreadB();
            b.setName("B");
            b.start();
    
        }
    
    }
    
    class Service {
    
        synchronized public static void printA() {
            try {
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "进入printA");
                Thread.sleep(3000);
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "离开printA");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        synchronized public static void printB() {
            System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
                    + System.currentTimeMillis() + "进入printB");
            System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
                    + System.currentTimeMillis() + "离开printB");
        }
    
    }
    
    
    class ThreadA extends Thread {
        @Override
        public void run() {
            Service.printA();
        }
    
    }
    
    
    class ThreadB extends Thread {
        @Override
        public void run() {
            Service.printB();
        }
    }

    运行结果:

    线程名称为:A1466149372909进入printA
    线程名称为:A1466149375920离开printA
    线程名称为:B在1466149375920进入printB
    线程名称为:B在1466149375920离开printB

    两个线程在争夺同一个类锁,因此同步

    6、synchronized (class)

    对上面Service类代码修改成如下:

    class Service {
    
        public static void printA() {
            synchronized (Service.class) {
                try {
                    System.out.println("线程名称为:" + Thread.currentThread().getName()
                            + "在" + System.currentTimeMillis() + "进入printA");
                    Thread.sleep(3000);
                    System.out.println("线程名称为:" + Thread.currentThread().getName()
                            + "在" + System.currentTimeMillis() + "离开printA");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
        }
    
        public static void printB() {
            synchronized (Service.class) {
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "进入printB");
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "离开printB");
            }
        }
    }

    运行结果:

    线程名称为:A1466149372909进入printA
    线程名称为:A1466149375920离开printA
    线程名称为:B在1466149375920进入printB
    线程名称为:B在1466149375920离开printB

    两个线程依旧在争夺同一个类锁,因此同步

    补充概念(反射)
    1.类名.class  是来自 反射的概念,类名.class是获得这个类所对应的Class实例。
    2.从面向对象的角度上来看,类也是对象,它们是类这个类对象,听起来有些抽象,但是在java中的实现就是所有的加载进来的类在虚拟机中都是一个java.lang.Class类的对象,而“类名.class”就是获得这个类的对象(在同一个ClassLoader中,类对象都是单例的)
    3.Class是对某个类的描述
    4.当虚拟机载入某个class文件时,首先生成该class文件对应的类的Class对象,即 对象描述类
    *******即可以理解为:类名.class 是获得这个类的 类描述对象(一个类对应只有一个类描述对象【对象里面是对类的描述】)
    

    需要特别说明:对于同一个类A,线程1争夺A对象实例的对象锁,线程2争夺类A的类锁,这两者不存在竞争关系。也就说对象锁和类锁互不干预内政

    静态方法则一定会同步,非静态方法需在单例模式才生效,但是也不能都用静态同步方法,总之用得不好可能会给性能带来极大的影响。另外,有必要说一下的是spring的bean默认是单例的。

    线程死锁

    死锁对Java程序来说,是很复杂的,也很难发现问题。当两个线程被阻塞,每个线程在等待另一个线程时就发生死锁。

    还是看一个比较直观的死锁例子:

    public class DeadlockRisk { 
        private static class Resource { 
            public int value; 
        } 
    
       private Resource resourceA = new Resource(); 
        private Resource resourceB = new Resource(); 
    
       public int read() { 
            synchronized (resourceA) { 
                synchronized (resourceB) { 
                    return resourceB.value + resourceA.value; 
                } 
            } 
        } 
    
      public void write(int a, int b) { 
            synchronized (resourceB) { 
                synchronized (resourceA) { 
                    resourceA.value = a; 
                    resourceB.value = b; 
                } 
            } 
        } 
    }

    假设read()方法由一个线程启动,write()方法由另外一个线程启动。读线程将拥有resourceA锁,写线程将拥有resourceB锁,两者都坚持等待的话就出现死锁。

    实际上,上面这个例子发生死锁的概率很小。因为在代码内的某个点,CPU必须从读线程切换到写线程,所以,死锁基本上不能发生。

    但是,无论代码中发生死锁的概率有多小,一旦发生死锁,程序就死掉。有一些设计方法能帮助避免死锁,包括始终按照预定义的顺序获取锁这一策略。

    展开全文
  • Java线程探究-Lock对象锁条件变量

    千次阅读 2017-04-12 18:08:50
    设想这样的一种情况,现在有一个盘子,一个线程负责往盘子里放一个苹果,一个线程从盘子取一个苹果,如何保证线程A放一个苹果,线程B就把这个苹果取了,不会出现已经放了好几个了,线程B才一个一个的取,现在限定一...
  • Java线程知识点总结

    千次阅读 2019-03-14 14:38:26
    文章目录Java线程知识点总结进程与线程线程的状态实现线程的几种方式进程和线程的区别Java进程和线程的关系Thread中的start和run方法的区别Thread和Runnable的关系如何实现处理线程的返回值volatile和...
  • Java线程中的对象互斥

    千次阅读 2018-01-07 15:16:36
    1、为什么会有锁? 在看线程同步的问题之前,我们先看一个生活中的小例子: 我拿着银行卡去ATM取钱,假如我的卡里有3000块,我取走2000,这个时候,ATM会去银行的数据库里查询我的账户是否有2000以上的余额,...
  • Java线程锁对象的改变

    千次阅读 2016-11-22 15:33:01
    在将任何数据类型作为同步锁时,需要注意的是,是否有多个线程同时持有锁对象,如果同时持有相同的锁对象,则这些线程之间就是同步的;如果分别获得锁对象,这些线程之间就是异步的。 这个时候线程A和B持有的锁都是...
  • Java线程的理解与使用

    万次阅读 多人点赞 2017-10-14 18:45:51
    作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchronized 和 ReentrantLock等 )
  • Java线程-6】synchronized同步

    千次阅读 2020-03-31 15:35:49
    前文描述了Java线程编程,多线程的方式提高了系统资源利用和程序效率,但多个线程同时处理共享的数据时,就将面临线程安全的问题。 例如,下面模拟这样一个场景:一个售票处有3个售票员,出售20张票。 public ...
  • java线程的15种

    万次阅读 多人点赞 2019-05-05 19:19:24
    1 java锁分类 下面我们依照序号依次的介绍每一种 2 悲观和乐观 悲观和乐观是一种广义的概念,体现的是看待线程同步的不同的角度 悲观认为自己在使用数据的时候,一定有别的线程来修改数据,在获取...
  • Java面试题大全(2020版)

    万次阅读 多人点赞 2019-11-26 11:59:06
    发现网上很多Java面试题都没有答案,所以花了很长时间搜集整理出来了这套Java面试题大全,希望对大家有帮助哈~ 本套Java面试题大全,全的不能再全,哈哈~ 一、Java 基础 1. JDK 和 JRE 有什么区别? JDK:Java ...
  • Java对象锁的理解

    万次阅读 热门讨论 2018-07-16 14:57:27
    1.类(synchronize(静态对象)):类的所有对象竞争。 2.方法(在方法前加synchronize): 同一对象同一方法需要竞争。 3.对象锁(synchronize(对象)):同一对象代码块竞争。 以上都是在学习Java锁的...
  • 并发干扰使用多线程开发可以很好地提高代码效率,但是在多线程对同一数据资源的共享中,许多线程需要的同一个数据做读写修改...线程 A :存入500元 线程 B :取出200元我们应该知道,在大多服务器操作系统中都采用抢
  • 首先整理多线程同步的知识点,开头肯定是先探讨探讨多线程同步的问题。那么嘛叫线程安全问题呢? 答: 我们知道Jvm虚拟机的设计中线程的执行是抢占式的,线程的执行时间是由底层系统决定的。所以就会有多个线程...
  • Java线程--多个对象多个

    千次阅读 热门讨论 2018-06-04 17:22:05
    上一篇博客中介绍了多个线程同时访问一个对象,产生一个对象锁,属于同步访问,现在介绍下如果是访问多个对象,会怎么执行那? Demo: HasSelfPrivateNum类: public class HasSelfPrivateNum { private int num=...
  • Java线程编程-(1)-线程安全和Synchronized概念

    万次阅读 多人点赞 2017-09-15 14:51:59
    一、进程与线程的概念 (1)在传统的操作系统中,程序并不能独立运行,作为资源分配和独立运行的基本单位都是进程。 在未配置 OS 的系统中,程序的执行方式是顺序执行,即必须在一个程序执行完后,才允许另一个...
  • Java线程同步:synchronized住的是代码还是对象

    万次阅读 多人点赞 2012-11-15 22:22:00
    Java中,synchronized关键字是用来控制线程同步的,就是在多线程的环境下,控制synchronized代码段不被多个线程同时执行。Synchronized既可以对代码块使用,也可以加在整个方法上。   关键是,不要认为给方法或者...
  • 我们将解决上一篇文章《Java线程安全和线程不安全解析和示例》中提到的线程不安全问题,看看通过synchronized的对象锁,怎样轻松解决该问题。 一.同步代码块 案例:通过同步代码块,实现两个线程对同一个全局...
  • Java线程-线程池-(lock)

    千次阅读 2019-03-12 10:34:33
    Java5当中,专门提供了锁对象,利用锁可以方便的实现对资源的封锁,用来控制对竞争资源并发访问控制,这些内容主要集中在java.util.concurrent.locks包下面,里面有三个重要的接口Condition、Lock、ReadWriteLock...
  • java线程什么时候释放

    千次阅读 2019-05-12 20:52:47
    由于等待一个锁定线程只有在获得这把之后,才能恢复运行,所以让持有线程在不需要的时候及时释放是很重要的。在以下情况下,持有线程会释放: 1、当前线程的同步方法、代码块执行结束的时候释放 ...
  • Java线程原理等

    千次阅读 2018-07-08 02:09:58
    Java线程应用一、 线程创建方式线程创建有二种方式,继承Thread、或者实现Runnable接口。继承Thread。 new Thread();public class MyThread extends Thread{ public MyThread(String name) { super(name); ...
  • JAVA-线程安全与机制详解

    千次阅读 2018-10-06 16:00:09
    只要一个不可变的对象被正确的构建出来,没有发生this引用逃逸,那其外部的可见状态永远不会改变,例如final修饰的对象JAVA API中常见的有String,Long,Double等 绝对线程安全 绝对线程安全达到不管运行时...
  • Java 面试之线程

    万次阅读 2018-09-03 15:22:51
    进程、线程 进程和线程的状态 进程:创建、就绪、执行、阻塞、终止 线程:就绪、执行、阻塞 实现多线程的几种方式 继承Thread类创建线程 实现Runnable接口创建线程 实现Callable接口创建新线程(可用...
  • Java 多线程 并发 Java线程面试题

    千次阅读 2018-05-12 00:02:12
    比如,如果一个线程完成一个任务100毫秒,那么用十个线程完成改任务只需10毫秒。Java在语言层面对多线程提供了卓越的支持,它也是一个很好的卖点。2) 线程和进程有什么区别?线程是进程的子集,一个进程可以有很多...
  • java线程安全和优化

    千次阅读 2016-04-10 16:17:43
    当多个线程访问一个对象时,如果不用考虑这些线程在运行环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象线程安全的 ...
  •  首先我这边是实际开发中使用到了,开发的环境情况:有一个数据中心(暂且当做一个Map集合),有两个子线程A、B,其中A线程每5秒钟从其他地方获取到新来的数据然后和数据中心里面的数据进行一个融合,然后B线程...
  • 1.在java线程编程中对象锁、类、同步机制synchronized详解:  对象锁:在java中每个对象都有一个唯一的对象锁用于对象实例方法或者一个对象实例上面的。  类:是用于一个类静态方法或者class对象的,一...
  • 关于对象锁、类以及争用情况的简单介绍
  • 考虑一个场景,在运行时你必须找到一个Java线程是否对特定的对象加锁,例如,确认NewsReader线程是否持有NewsPaper对象?如果这个问题出现在任何核心的Java面试中,那么我会自动假设可能有至少两个答案,一个是...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 305,120
精华内容 122,048
关键字:

java线程锁为什么要对象

java 订阅