线程同步的方法包括_线程的同步和异步的区别

线程同步的方法包括_线程的同步和异步的区别多线程—7种同步方法关于线程同步(7种方式) 同步方法同步代码块使用重入锁实现线程同步(ReentrantLock)使用特殊域变量(volatile)实现同步(每次重新计算,安全但并非一致)使用局部变量实现线程同步(ThreadLocal)

多线程—7种同步方法   关于线程同步(7种方式) 同步方法 同步代码块 使用重入锁实现线程同步(ReentrantLock) 使用特殊域变量(volatile)实现同步(每次重新计算,安全但并非一致) 使用局部变量实现线程同步(ThreadLocal)以空间换时间 使用原子变量实现线程同步(AtomicInteger(乐观锁)) 使用阻塞队列实现线程同步(BlockingQueue (常用)add(),offer(),put()   =========================================   为何要使用同步?       java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查),       将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前,被其他线程的调用,       从而保证了该变量的唯一性和准确性。         1.同步方法       即有synchronized关键字修饰的方法。       由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,       内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。           代码如:       public synchronized void save(){}          注: synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类         2.同步代码块       即有synchronized关键字修饰的语句块。       被该关键字修饰的语句块会自动被加上内置锁,从而实现同步           代码如:       synchronized(object){       }           注:同步是一种高开销的操作,因此应该尽量减少同步的内容。       通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。                代码实例:            
线程同步的方法包括_线程的同步和异步的区别
线程同步的方法包括_线程的同步和异步的区别   package com.xhj.thread;             /        * 线程同步的运用        *        * @author XIEHEJUN        *        */       public class SynchronizedThread {                 class Bank {                     private int account = 100;                     public int getAccount() {                   return account;               }                     /                * 用同步方法实现                *                * @param money                */               public synchronized void save(int money) {                   account += money;               }                     /                * 用同步代码块实现                *                * @param money                */               public void save1(int money) {                   synchronized (this) {                       account += money;                   }               }           }                 class NewThread implements Runnable {               private Bank bank;                     public NewThread(Bank bank) {                   this.bank = bank;               }                     @Override               public void run() {                   for (int i = 0; i < 10; i++) {                       // bank.save1(10);                       bank.save(10);                       System.out.println(i + “账户余额为:” + bank.getAccount());                   }               }                 }                 /            * 建立线程,调用内部类            */           public void useThread() {               Bank bank = new Bank();               NewThread new_thread = new NewThread(bank);               System.out.println(“线程1”);               Thread thread1 = new Thread(new_thread);               thread1.start();               System.out.println(“线程2”);               Thread thread2 = new Thread(new_thread);               thread2.start();           }                 public static void main(String[] args) {               SynchronizedThread st = new SynchronizedThread();               st.useThread();           }             }   
线程同步的方法包括_线程的同步和异步的区别
线程同步的方法包括_线程的同步和异步的区别   3.使用重入锁实现线程同步   在JavaSE5.0中新增了一个java.util.concurrent包来支持同步。       ReentrantLock类是可重入、互斥、实现了Lock接口的锁,       它与使用synchronized方法和块具有相同的基本行为和语义,并且扩展了其能力   
线程同步的方法包括_线程的同步和异步的区别
线程同步的方法包括_线程的同步和异步的区别          ReentrantLock类的常用方法有:           ReentrantLock() : 创建一个ReentrantLock实例           lock() : 获得锁           unlock() : 释放锁       注:ReentrantLock()还有一个可以创建公平锁的构造方法,但由于能大幅度降低程序运行效率,不推荐使用                   例如:           在上面例子的基础上,改写后的代码为:                   代码实例:            
线程同步的方法包括_线程的同步和异步的区别
线程同步的方法包括_线程的同步和异步的区别   //只给出要修改的代码,其余代码与上同           class Bank {                               private int account = 100;               //需要声明这个锁               private Lock lock = new ReentrantLock();               public int getAccount() {                   return account;               }               //这里不再需要synchronized               public void save(int money) {                   lock.lock();                   try{                       account += money;                   }finally{                       lock.unlock();                   }                                   }           }   
线程同步的方法包括_线程的同步和异步的区别
线程同步的方法包括_线程的同步和异步的区别                     注:关于Lock对象和synchronized关键字的选择:           a.最好两个都不用,使用一种java.util.concurrent包提供的机制,               能够帮助用户处理所有与锁相关的代码。           b.如果synchronized关键字能满足用户的需求,就用synchronized,因为它能简化代码           c.如果需要更高级的功能,就用ReentrantLock类,此时要注意及时释放锁,否则会出现死锁,通常在finally代码释放锁      4.使用特殊域变量(volatile)实现线程同步       a.volatile关键字为域变量的访问提供了一种免锁机制,       b.使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新,       c.因此每次使用该域就要重新计算,而不是使用寄存器中的值       d.volatile不会提供任何原子操作,它也不能用来修饰final类型的变量               例如:           在上面的例子当中,只需在account前面加上volatile修饰,即可实现线程同步。               代码实例:            
线程同步的方法包括_线程的同步和异步的区别
线程同步的方法包括_线程的同步和异步的区别         //只给出要修改的代码,其余代码与上同           class Bank {               //需要同步的变量加上volatile               private volatile int account = 100;                     public int getAccount() {                   return account;               }               //这里不再需要synchronized               public void save(int money) {                   account += money;               }           }   
线程同步的方法包括_线程的同步和异步的区别
线程同步的方法包括_线程的同步和异步的区别           注:多线程中的非同步问题主要出现在对域的读写上,如果让域自身避免这个问题,则就不需要修改操作该域的方法。       用final域,有锁保护的域和volatile域可以避免非同步的问题。   可见性:可见性在java内存模型中有定义,可以参看。   普通变量则没有,他们在线程之间的交互是通过主内存来完成,volatile变量则是通过主内存完成交换,但是两者区别在于volatile变量能立即同步到主内存中,当一个线程修改变量的变量的时候,立刻会被其他线程感知到。   特别注意一点:volatile变量的可见性经常性被误解,认为,valotile变量在各个线程中是一致的。所以基于volatile变量是安全的。这种认为是错误的。论据是正确的,但是得出的是安全的就不正确了。不会存在不一致性问题(在各个的工作内存中可以存在不一致的情况,但是由于每次使用之前都要刷新,执行引擎看不到不一致的问题,因此认为不存在不一致的问题)但是java里面的运算中并非原子操作,导致volatile变量的运算在并发下一样不安全。         实现可见性方式: 1.volatile   2.synchronized    3.final                               5.使用局部变量实现线程同步       如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本,       副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。变量局部化。   java.lang   类 ThreadLocal<T>   java.lang.Object     java.lang.ThreadLocal<T>   直接已知子类:   InheritableThreadLocal       ThreadLocal 类的常用方法             ThreadLocal() : 创建一个线程本地变量       get() : 返回此线程局部变量的当前线程副本中的值       initialValue() : 返回此线程局部变量的当前线程的”初始值”       set(value) : 将此线程局部变量的当前线程副本中的值设置为value             例如:           在上面例子基础上,修改后的代码为:                   代码实例:                
线程同步的方法包括_线程的同步和异步的区别
线程同步的方法包括_线程的同步和异步的区别   //只改Bank类,其余代码与上同           public class Bank{               //使用ThreadLocal类管理共享变量account               private static ThreadLocal<Integer> account = new ThreadLocal<Integer>(){                   @Override                   protected Integer initialValue(){                       return 100;                   }               };               public void save(int money){                   account.set(account.get()+money);               }               public int getAccount(){                   return account.get();               }           }   
线程同步的方法包括_线程的同步和异步的区别
线程同步的方法包括_线程的同步和异步的区别       注:ThreadLocal与同步机制           a.ThreadLocal与同步机制都是为了解决多线程中相同变量的访问冲突问题。           b.前者采用以”空间换时间”的方法,后者采用以”时间换空间”的方式               6.使用原子变量实现线程同步         需要使用线程同步的根本原因在于对普通变量的操作不是原子的。       那么什么是原子操作呢?   原子操作就是指将读取变量值、修改变量值、保存变量值看成一个整体来操作   即-这几种行为要么同时完成,要么都不完成。       在java的util.concurrent.atomic包中提供了创建了原子类型变量的工具类,   使用该类可以简化线程同步。小工具包,支持在单个变量上解除锁的线程安全编程。           类摘要   AtomicBoolean   可以用原子方式更新的 boolean 值。   AtomicInteger   可以用原子方式更新的 int 值。   AtomicIntegerArray   可以用原子方式更新其素的 int 数组。   AtomicIntegerFieldUpdater<T>   基于反射的实用工具,可以对指定类的指定 volatile int 字段进行原子更新。   AtomicLong   可以用原子方式更新的 long 值。   AtomicLongArray   可以用原子方式更新其素的 long 数组。   AtomicLongFieldUpdater<T>   基于反射的实用工具,可以对指定类的指定 volatile long 字段进行原子更新。   AtomicMarkableReference<V>   AtomicMarkableReference 维护带有标记位的对象引用,可以原子方式对其进行更新。   AtomicReference<V>   可以用原子方式更新的对象引用。   AtomicReferenceArray<E>   可以用原子方式更新其素的对象引用数组。   AtomicReferenceFieldUpdater<T,V>   基于反射的实用工具,可以对指定类的指定 volatile 字段进行原子更新。   AtomicStampedReference<V>   AtomicStampedReference 维护带有整数”标志”的对象引用,可以用原子方式对其进行更新。           其中AtomicInteger(乐观锁)为例 :   表可以用原子方式更新int的值,可用在应用程序中(如以原子方式增加的计数器),但不能用于替换Integer;可扩展Number,允许那些处理机遇数字类的工具和实用工具进行统一访问。   AtomicInteger类常用方法:   AtomicInteger(int initialValue) : 创建具有给定初始值的新的AtomicInteger   addAndGet(int dalta) : 以原子方式将给定值与当前值相加   int   getAndAdd(int delta)   以原子方式将给定值与当前值相加。   int   getAndDecrement()   以原子方式将当前值减 1。   int   getAndIncrement()   以原子方式将当前值加 1。       int get() : 当前值   set():设置给定初始值   代码实例:   只改Bank类,其余代码与上面第一个例子同   
线程同步的方法包括_线程的同步和异步的区别
线程同步的方法包括_线程的同步和异步的区别    1 class Bank {    2         private AtomicInteger account = new AtomicInteger(100);    3    4         public AtomicInteger getAccount() {    5             return account;    6         }    7    8         public void save(int money) {                                                 //以原子方式将给定值与当前值相加    9             account.addAndGet(money);   10         }   11     }     7.使用阻塞队列实现线程同步         阻塞队列与普通队列的区别在于,当队列是空的时,从队列中素的操作将会被阻塞,或者当队列是满时,往队列里添加素的操作会被阻塞。试图从空的阻塞队列中素的线程将会被阻塞,直到其他的线程往空的队列插入新的素。同样,试图往已满的阻塞队列中添加新素的线程同样也会被阻塞,直到其他的线程使队列重新变得空闲起来,如从队列中移除一个或者多个素,或者完全清空队列,同时,阻塞队列里面的put、take方法是被加:synchronized 同步限制,下图展示了如何通过阻塞队列来合作:              
线程同步的方法包括_线程的同步和异步的区别
线程同步的方法包括_线程的同步和异步的区别   add()方法会抛出异常  offer()方法返回false  put()方法会阻塞   二、几种常见阻塞队列     1、BlockingQueue (常用)        素的时候等待队列里有素,否则阻塞         保存素的时候等待队列里有空间,否则阻塞         用来简化生产者消费者在多线程环境下的开发     2、ArrayBlockingQueue (数组阻塞队列)       FIFO、数组实现        有界阻塞队列,一旦指定了队列的长度,则队列的大小不能被改变        在生产者消费者例子中,如果生产者生产实体放入队列超过了队列的长度,则在offer(或者put,add)的时候会被阻塞,直到队列的实体数量< 队列的         初始size为止。不过可以设置超时时间,超时后队列还未空出位置,则offer失败。        如果消费者发现队列里没有可被消费的实体时也会被阻塞,直到有实体被生产出来放入队列位置,不过可以设置等待的超时时间,超过时间后会返       回null       3、DelayQueue (延迟队列)        有界阻塞延时队列,当队列里的素延时期未到是,通过take方法不能,会被阻塞,直到有素延时到期为止         如:          1.obj 5s 延时到期          2.obj 6s 延时到期          3.obj 9s 延时到期        那么在take的时候,需要等待5秒钟才能第一个obj,再过1s后可以第二个obj,再过3s后可以获得第三个obj        这个队列可以用来处理session过期失效的场景,比如session在创建的时候设置延时到期时间为30分钟,放入延时队列里,然后通过一个线程来获       取这个队列素,只要能被到的,表示已经是过期的session,被的session可以肯定超过30分钟了,这时对session进行失效。          4、LinkedBlockingQueue (链表阻塞队列)        FIFO、Node链表结构         可以通过构造方法设置capacity来使得阻塞队列是有界的,也可以不设置,则为无界队列         其他功能类似ArrayBlockingQueue     5、PriorityBlockingQueue (优先级阻塞队列)       无界限队列,相当于PriorityQueue + BlockingQueue        插入的对象必须是可比较的,或者通过构造方法实现插入对象的比较器Comparator<? super E>        队列里的素按Comparator<? super E> comparator比较结果排序,PriorityBlockingQueue可以用来处理一些有优先级的事物。比如短信发送优先     级队列,队列里已经有某企业的条短信,这时候又来了一个100条紧急短信,优先级别比较高,可以通过PriorityBlockingQueue来轻松实现       这样的功能。这样这个100条可以被优先发送              前面5种同步方式都是在底层实现的线程同步,但是我们在实际开发当中,应当尽量远离底层结构。        使用javaSE5.0版本中新增的java.util.concurrent包将有助于简化开发。        本小节主要是使用LinkedBlockingQueue<E>来实现线程的同步        LinkedBlockingQueue<E>是一个基于已连接节点的,范围任意的blocking queue。        队列是先进先出的顺序(FIFO),关于队列以后会详细讲解~                LinkedBlockingQueue 类常用方法        LinkedBlockingQueue() : 创建一个容量为Integer.MAX_VALUE的LinkedBlockingQueue        put(E e) : 在队尾添加一个素,如果队列满则阻塞        size() : 返回队列中的素个数        take() : 移除并返回队头素,如果队列空则阻塞                代码实例:            实现商家生产商品和买卖商品的同步   
线程同步的方法包括_线程的同步和异步的区别
线程同步的方法包括_线程的同步和异步的区别    1 package com.xhj.thread;    2    3 import java.util.Random;    4 import java.util.concurrent.LinkedBlockingQueue;    5    6 /    7  * 用阻塞队列实现线程同步 LinkedBlockingQueue的使用    8  *    9  * @author XIEHEJUN   10  *   11  */   12 public class BlockingSynchronizedThread {   13     /   14      * 定义一个阻塞队列用来存储生产出来的商品   15      */   16     private LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<Integer>();   17     /   18      * 定义生产商品个数   19      */   20     private static final int size = 10;   21     /   22      * 定义启动线程的标志,为0时,启动生产商品的线程;为1时,启动消费商品的线程   23      */   24     private int flag = 0;   25   26     private class LinkBlockThread implements Runnable {   27         @Override   28         public void run() {   29             int new_flag = flag++;   30             System.out.println(“启动线程 ” + new_flag);   31             if (new_flag == 0) {   32                 for (int i = 0; i < size; i++) {   33                     int b = new Random().nextInt(255);   34                     System.out.println(“生产商品:” + b + “号”);   35                     try {   36                         queue.put(b);   37                     } catch (InterruptedException e) {   38                         // TODO Auto-generated catch block   39                         e.printStackTrace();   40                     }   41                     System.out.println(“仓库中还有商品:” + queue.size() + “个”);   42                     try {   43                         Thread.sleep(100);   44                     } catch (InterruptedException e) {   45                         // TODO Auto-generated catch block   46                         e.printStackTrace();   47                     }   48                 }   49             } else {   50                 for (int i = 0; i < size / 2; i++) {   51                     try {   52                         int n = queue.take();   53                         System.out.println(“消费者买去了” + n + “号商品”);   54                     } catch (InterruptedException e) {   55                         // TODO Auto-generated catch block   56                         e.printStackTrace();   57                     }   58                     System.out.println(“仓库中还有商品:” + queue.size() + “个”);   59                     try {   60                         Thread.sleep(100);   61                     } catch (Exception e) {   62                         // TODO: handle exception   63                     }   64                 }   65             }   66         }   67     }   68   69     public static void main(String[] args) {   70         BlockingSynchronizedThread bst = new BlockingSynchronizedThread();   71         LinkBlockThread lbt = bst.new LinkBlockThread();   72         Thread thread1 = new Thread(lbt);   73         Thread thread2 = new Thread(lbt);   74         thread1.start();   75         thread2.start();   76   77     }   78   79 }   
线程同步的方法包括_线程的同步和异步的区别
线程同步的方法包括_线程的同步和异步的区别         注:BlockingQueue<E>定义了阻塞队列的常用方法,尤其是三种添加素的方法,我们要多加注意,当队列满时:   add()方法会抛出异常   offer()方法返回false   put()方法会阻塞                

2024最新激活全家桶教程,稳定运行到2099年,请移步至置顶文章:https://sigusoft.com/99576.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。 文章由激活谷谷主-小谷整理,转载请注明出处:https://sigusoft.com/61576.html

(0)
上一篇 2024年 8月 29日 上午8:04
下一篇 2024年 8月 29日

相关推荐

关注微信