精华内容
下载资源
问答
  • java线程同步

    2015-09-25 14:14:41
    java线程同步:synchronized、Lock、可重入锁ReentrantLock: http://outofmemory.cn/java/java.util.concurrent/synchronized-locks-Lock-ReentrantLock 一 synchronized关键字 1.synchronized实现原理: ...

    java线程同步:synchronized、Lock、可重入锁ReentrantLock:

    http://outofmemory.cn/java/java.util.concurrent/synchronized-locks-Lock-ReentrantLock

    一 synchronized关键字

    1.synchronized实现原理: ---基于对象监视器(锁)

    java中所有对象都自动含有单一的锁,JVM负责跟踪对象被加锁的次数。如果一个对象被解锁,其计数变为0。在任务(线程)第一次给对象加锁的时候, 计数变为1。每当这个相同的任务(线程)在此对象上获得锁时,计数会递增。只有首先获得锁的任务(线程)才能继续获取该对象上的多个锁。每当任务离开时,计数递减,当计数为0的时候,锁被完全释放。

    Java中每个对象或者类都有一把锁与之相关联,对于对象来说,监视的是这个对象的实例变量,对于类来说,监视的是类变量(一个类本身是类Class的对象,所以与类关联的锁也是对象锁)

     

    一个线程执行互斥代码过程如下:

            1. 获得同步锁;

            2. 清空工作内存;

            3. 从主内存拷贝对象副本到工作内存;

            4. 执行代码(计算或者输出等);

            5. 刷新主内存数据;

            6. 释放同步锁。

            所以,synchronized既保证了多线程的并发有序性,又保证了多线程的内存可见性。

     

    2.使用方式:

    synchronized关键字使用方式有两种:synchronized方法synchronized块。这两种监视区域都和一个引入对象相关联,当到达这个监视区域时,JVM就会锁住这个引用对象,当离开时会释放这个引用对象上的锁(有异常退出时,JVM会释放锁)。对象锁是JVM内部机制,只需要编写同步方法或者同步块即可,操作监视区域时JVM会自动获取锁或者释放锁。

      当synchronized作用在方法上时,锁住的便是对象实例(this);当作用在静态方法时锁住的便是对象对应的Class实例(类)。

     

     

    二 JavaSE5.0中新增了一个java.util.concurrent包来支持同步,ReentrantLock类。

    1.ReentrantLock类

    ReenreantLock类的常用方法有:
    ReentrantLock() : 创建一个ReentrantLock实例 
    lock() : 获得锁 
    unlock() : 释放锁 
    注:ReentrantLock()还有一个可以创建公平锁的构造方法,但由于能大幅度降低程序运行效率,不推荐使用

     

     

    两种多线程同步机制的代码实现:

    package com.test1;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class ThreadTest {
    
        public ThreadTest(){
            Bank b=new Bank();        
            Thread t1=new Thread(b);
            Thread t2=new Thread(b);
            Thread t3=new Thread(b);        
            t1.start();
            t2.start();
            t3.start();
        }
        
        public static void main(String[] args) {
            
            ThreadTest threadTest=new ThreadTest();
            
        }
            
    }
        
    class Bank implements Runnable{
            
            private int account=100;
            
            //线程同步机制1:线程同步方法 synchronized 或者 synchronized{} 修饰共享变量的执行 语句块
            public synchronized void minus_syn(){                
                        account--;
                        System.out.println(Thread.currentThread().getName()+" account="+account);                 
            }
            
            //线程同步机制2:使用 重入锁 实现线程同步
            /**
             * 
        在JavaSE5.0中新增了一个java.util.concurrent包来支持同步。   ReentrantLock类是可重入、互斥、实现了Lock接口的锁, 
        它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力  
        ReenreantLock类的常用方法有:
            ReentrantLock() : 创建一个ReentrantLock实例 
            lock() : 获得锁 
            unlock() : 释放锁 
        注:ReentrantLock()还有一个可以创建公平锁的构造方法,但由于能大幅度降低程序运行效率,不推荐使用 
             */
            private Lock lock = new ReentrantLock();        
            public  void minus_lock(){
                   lock.lock();
                    try{
                        account--;
                        System.out.println(Thread.currentThread().getName()+" account="+account);
                    }finally{
                        lock.unlock();
                    }                     
            }
            
            @Override
            public void run() {
                // TODO Auto-generated method stub
                while(true){
                     
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    
                /*    synchronized 同步块
                 * 
                 * synchronized (this) {
                            
                        if(account>0){
                            account-=1;
                            System.out.println(Thread.currentThread().getName()+" account="+account);            
                            }
                        else break;                    
                    }*/
                    
                    
                    /*synchronized 方法
                     * 
                     * minus_syn();
                    if(account<0) break;*/
                    
                    //   ReentrantLock类 lock
                    minus_lock();
                    if(account<0) break;
                                      
                }
            }
        }
        
    
     

     

    (转!)总结:

    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语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。

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

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

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



    展开全文
  • Java线程同步

    千次阅读 2018-01-06 17:56:53
    上一篇主要介绍了在Java中使用多线程,这一篇将总结Java线程的同步 线程同步 最典型的例子就是银行取钱例子,两个线程同时取钱的时候会出现余额小于0的情况,即并发线程“同时”修改了共享对象的成员变量,为了...

    上一篇主要介绍了在Java中使用多线程,这一篇将总结Java线程的同步

    线程同步

    最典型的例子就是银行取钱例子,两个线程同时取钱的时候会出现余额小于0的情况,即并发线程“同时”修改了共享对象的成员变量,为了解决这个问题,Java提供了同步代码块和同步方法。

    //同步代码块
    synchronized(obj){
    
    }
    
    //同步方法
    [public] synchronized returntype methodName(){
    
    }

    在线程执行同步代码块或同步方法之前首先要得到锁,任何时候只有一个线程可以得到锁,该线程在执行完同步代码块中的代码之后就会释放锁资源

    对于同步方法,非静态的同步方法,以this即调用方法的对相对为同步监视器,也就是说,在执行同步方法之前,首先需要对调用同步方法的对象加锁,在执行完同步方法后释放锁。对于静态的同步方法,以class对象为同步监视器。

    需要注意的是不要对线程安全类的所有方法都进行同步,只有那些改变共享资源(成员变量)的方法需要被同步,同步方法保证了线程安全,但是效率有所牺牲,就像JDK中的StringBuilder和StringBuffer两个类一样,所以应该考虑运行环境(多线程和单线程)设计两个不同的版本

    锁释放的时机

    1. 当同步代码块或同步方法执行完毕的时候释放锁
    2. 在同步代码块或同步方法中出现了未处理的Error或Exception,此时当前的线程将会释放对同步监视器的锁定
    3. 执行了同步监视器的wait方法

    在如下的几种情况下锁不会被释放
    - 在同步代码块或同步方法执行过程中,调用sleep和yield方法
    - 其他线程调用执行同步代码块的suspend方法将线程挂起

    同步锁

    Lock对象是控制多个线程对共享资源访问的工具,每次只有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象

    比较常用的Lock和ReadWriteLock两个根接口下的实现类ReentrantLock和ReentrantReadWriteLock

    使用ReentrantLock的代码实例

    class X{
        private final ReentrantLock lock = new ReentrantLock();
        public void m(){
            //加锁
            lock.lock();
            try{
                //业务代码 保证了线程安全
            }
            finally{
                //释放锁资源
                lock.unlock();
            }
        }
    }

    使用Lock对象和使用同步方法是相似的,只是使用Lock时显示地使用了Lock对象作为同步锁,而使用同步方法时隐式地使用了当前对象作为同步监视器,两者都保证了在同一个调用对象的情况下,每次只有一个线程能够访问临界区

    ReentrantLock和ReentrantReadWriteLock具有可重入性,也就是说,一个线程可以对已被加锁的ReentrantLock再次加锁,ReentrantLock对象会维持一个计数器,来统计lock方法的嵌套,线程每次调用lock方法后都必须使用unlock方法来释放锁,简单的来说,一段被加锁的代码可以调用另一段被相同锁保护的代码

    method A(){
        lock.lock();
        try{
            method B(); //B方法可以同样是被lock保护的一段代码
        }finally{
            lock.unlock();
        }
    }

    死锁

    死锁的成因主要是线程之间相互占有对方所需要的资源而不释放,一旦出现死锁,所有线程处于阻塞的状态,无法继续

    在同时需要多个同步监视器的情况下,死锁比较容易出现

    一个死锁的实例

    public class DeadLock implements Runnable {
        private A a = new A();
        private B b = new B();
    
        public void init() {
            Thread.currentThread().setName("主线程");
            a.foo(b);
            System.out.println("进入主线程之后");
        }
    
        @Override
        public void run() {
            Thread.currentThread().setName("副线程");
            b.foo(a);
            System.out.println("进入副线程之后");
    
        }
    
        public static void main(String[] args) {
            DeadLock dlock = new DeadLock();
            new Thread(dlock).start();
            dlock.init();
        }
    }
    
    class A {
        public synchronized void foo(B b) {
            System.out.println("当前线程名:" + Thread.currentThread().getName() + "进入A的foo方法");
            try {
                Thread.sleep(200);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("当前线程名:" + Thread.currentThread().getName() + "将要进入B的last方法");
            b.last();
        }
    
        public synchronized void last() {
            System.out.println("进入了A的last方法");
        }
    }
    
    class B {
        public synchronized void foo(A a) {
            System.out.println("当前线程名:" + Thread.currentThread().getName() + "进入B的foo方法");
            try {
                Thread.sleep(200);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("当前线程名:" + Thread.currentThread().getName() + "将要进入A的last方法");
            a.last();
        }
    
        public synchronized void last() {
            System.out.println("进入了B的last方法");
        }
    }
    

    输出(程序没有结束)

    当前线程名:主线程进入A的foo方法
    当前线程名:副线程进入B的foo方法
    当前线程名:主线程将要进入B的last方法
    当前线程名:副线程将要进入A的last方法

    分析一下上面的程序可以发现,
    1. 当主线程调用dlock对象的init方法,这个时候调用A的foo方法,对象a作为同步方法的同步监视器被加上了锁
    2. 此时主线程被sleep,
    3. 执行b对象的foo方法,同样的,b对象被当成同步监视器被加锁,
    4. 接着副线程sleep,
    5. 主线程被分配到时间片,将要进入b对象的last方法,但是b对象的锁没有被释放掉,因此主线程被阻塞,
    6. 同样的,副线程想要调用a对象的last方法同样因为a对象的锁没有被释放,副线程被阻塞,程序因此进入死锁的状态不能继续执行

    展开全文
  • Java 线程同步

    2017-07-25 15:40:33
    线程同步:保证多个线程同时读取一个类中的共享数据的线程安全 Java所有对象都有一个内置锁,使用 synchronized 关键字修饰方法或代码块时将为当前对象加锁,一个线程获取锁后,其他线程需要等待该线程执行完毕后解锁...
    线程同步:保证多个线程同时读取一个类中的共享数据的线程安全
    Java所有对象都有一个内置锁,使用 synchronized 关键字修饰方法或代码块时将为当前对象加锁,一个线程获取锁后,其他线程需要等待该线程执行完毕后解锁。
    修饰方法:
    private synchronized void function() {}
    修饰代码块:
    private void function() {
        synchronized (object) {}
    }

    锁加在 object 对象上面。该对象可以是当前对象(object == this),也可以是当前类的Class对象(object == MyClass.class)

    简单例子,多线程操作同一账户

    线程类:

    public class SynchronizedThread extends Thread {
    
    	private Account account;
    	private int cash;
    
    	public SynchronizedThread(String name, Account account, int cash) {
    		super(name);
    		this.account = account;
    		this.cash = cash;
    	}
    
    	@Override
    	public void run() {
    		account.plus(cash);
    	}
    
    	public static void main(String[] args) {
    		Account at = new Account(100);
    		for (int i = 0; i < 5; i++) {
    			new SynchronizedThread("A" + i, at, -10).start();
    		}
    	}
    
    }

    账户类(未同步):

    public class Account {
    
    	private int money;
    
    	public Account(int money) {
    		this.money = money;
    	}
    
    	// 业务方法
    	public void plus(int cash) {
    		try {
    			int last = money;
    			Thread.sleep(1); // 模拟一个延迟
    			money += cash;
    			System.out.println(Thread.currentThread().getName() + ": 钱包: " + last + " 消费: " + cash + " 余额: " + money);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    
    }

    未同步时,运行结果:


    进行线程同步后:

    同步方法:

    public synchronized void plus(int cash) {
    		try {
    			int last = money;
    			Thread.sleep(1); // 模拟一个延迟
    			money += cash;
    			System.out.println(Thread.currentThread().getName() + ": 钱包: " + last + " 消费: " + cash + " 余额: " + money);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    或同步代码块:
    public void plus(int cash) {
    		try {
    			synchronized (this) {
    				int last = money;
    				Thread.sleep(1); // 模拟一个延迟
    				money += cash;
    				System.out.println(Thread.currentThread().getName() + ": 钱包: " + last + " 消费: " + cash + " 余额: " + money);
    			}
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    运行结果:



    展开全文
  • JAVA线程同步

    千次阅读 2011-01-14 22:26:00
    线程同步控制主要通过: synchronized wait() notify() notifyAll(); 关键字syschronized 是对每个对象都有一把锁,当有多个线程同时访问共享资源的时候,需要syschronized 来控制安全性。 ...

    展开全文
  • java线程同步问题,当时线程同步,为什么要锁定当前对象只锁定需要同步的代码不行吗?谁能解释一下为什么?
  • JAVA线程同步锁和线程间协调操作

    千次阅读 2017-08-05 11:32:58
    java线程同步锁和线程间协调操作
  • 本文详细介绍了Java线程同步的概念以及常用方法,重点介绍了同步块和同步函数。
  • JAVA线程同步方法和同步代码块

    千次阅读 2018-08-08 16:35:58
    JAVA 线程同步方法和同步代码块 线程安全和非线程安全 脏读 非线程安全:多个线程对同一个对象的中的实例变量进行并发访问,产生后果就是脏读,也就是获取的数据被更改。 非线程安全问题存在与“实例变量”中,...
  • Java 线程同步与死锁 学习笔记

    千次阅读 2016-09-25 10:02:24
    Java 线程同步与死锁 学习笔记Java 线程同步与死锁 学习笔记 1 多线程共享数据 2 线程同步 3 同步准则 4 线程死锁 1、 多线程共享数据 在多线程操作中,多个线程可能同时处理同一个资源,这就是多线程中的共享数据。...
  • java线程同步原理

    千次阅读 2012-09-12 14:43:31
    java线程同步原理 java会为每个object对象分配一个monitor,当某个对象的同步方法(synchronized methods)被多个线程调用时,该对象的monitor将负责处理这些访问的并发独占要求。 当一个线程调用一个对象的同步...
  • JAVA 线程 同步 信号量

    千次阅读 2011-05-02 17:29:00
    JAVA 线程 同步 信号量
  • Java线程同步方式和线程本地变量——Java经典面试题(其二)实现线程同步的几种方式1.为何要使用同步? Java允许多线程并发控制,当多个线程同时操作一个可共享资源变量时(如数据的增删改查),将会导致数据不...
  • 线程同步实现多个线程同步访问同一个数据结构为了防止多个线程同时访问同一个数据结构导致数据结构被破坏,同一时间只允许一个线程操作这个数据结构,使用监视器(monitor),Java每个对象都有一个监视器,可以将线程...
  • Java线程同步之重入锁

    千次阅读 2014-04-30 16:09:48
    java线程同步除了原子变量,sync
  • java线程 同步与异步 线程池   博客分类: JAVA多线程 Executors   1)多线程并发时,多个线程同时请求同一个资源,必然导致此资源的数据不安全,A线程修改了B线 程的处理的数据,而B线程又...
  • 为何要使用Java线程同步?Java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时,将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前,被其他线程的调用,从而保证...
  • Java线程同步中关键字synchronized简述

    千次阅读 2015-10-14 13:40:49
    Java线程同步中关键字synchronized简述 一、作用: synchronized关键字通过修饰一个方法或者声明一个代码块,从而产生一个同步对象锁以及对应的同步代码块。每当有线程要对该同步代码块进行访问时,线程就...
  • java线程同步的实现方式

    千次阅读 2019-03-08 01:47:21
    这里抛砖引玉,为何要使用同步?...下面总结一些java线程实现同步方式,大致有下面几种: 1.同步方法 使用 synchronized关键字,可以修饰普通方法、静态方法,以及语句块。由于java的每个对象都有一个内置锁...
  • 【0】README0.1) 本文描述转自 core java volume 1, 源代码为原创,旨在理解 java线程同步——竞争条件的荔枝+锁对象 的相关知识; 0.2)for full source code : ...
  • java线程 同步临界区:thinking in java4 21.3.5 thinking in java 4免费下载:http://download.csdn.net/detail/liangrui1988/7580155
  • 线程的同步与互斥(同步线程与异步线程,线程同步和异步问题) Java 虚拟机中的同步(Synchronization)基于进入和退出管程(Monitor)对象实现, 无论是显式同步(有明确的 monitorenter 和 monitorexit 指令,即同...
  • java线程同步详解

    千次阅读 2016-05-27 22:05:02
    (3)使用特殊域变量(Volatile)实现线程同步 a. volatile 关键字为域变量的访问提供了一种免锁机制 b.使用 volatile 修饰域相当于告诉虚拟机该域可能会被其他线程更新 c.因此每次使用该域就要重新计算,而不是...
  • 如何解决Java线程同步中的阻塞问题

    千次阅读 2012-03-30 20:29:00
    Java线程同步需要我们不断的进行相关知识的学习,下面我们就来看看如何才能更好的在学习中掌握相关的知识讯息,来完善我们自身的编写手段。希望大家有所收获。  Java线程同步的优先级代表该线程的重要程度,当有多...
  • Java 线程同步 synchronized

    千次阅读 2013-05-26 16:02:58
    先来看一个不带线程同步的例子,这个例子很简单,只是让两个线程输出同样的内容,并不做其他的事,所以,线程同步在这里体现的并不明显。 import java.util.Date; public class ThreadTest extends Thread{ int...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 53,436
精华内容 21,374
关键字:

java线程同步

java 订阅