zoukankan      html  css  js  c++  java
  • 转:关于JAVA多线程同步

    转:http://lanvis.blog.163.com/blog/static/26982162009798422547/

    因为需要,最近关注了一下JAVA多线程同步问题。JAVA多线程同步主要依赖于若干方法和关键字。将心得记录如下:



    1  wait方法:
            该方法属于Object的方法,wait方法的作用是使得当前调用wait方法所在部分(代码块)的线程停止执行,并释放当前获得的调用wait所在的代码块的锁,并在其他线程调用notify或者notifyAll方法时恢复到竞争锁状态(一旦获得锁就恢复执行)。
            调用wait方法需要注意几点:
            第一点:wait被调用的时候必须在拥有锁(即synchronized修饰的)的代码块中。
            第二点:恢复执行后,从wait的下一条语句开始执行,因而wait方法总是应当在while循环中调用,以免出现恢复执行后继续执行的条件不满足却继续执行的情况。
            第三点:若wait方法参数中带时间,则除了notify和notifyAll被调用能激活处于wait状态(等待状态)的线程进入锁竞争外,在其他线程中interrupt它或者参数时间到了之后,该线程也将被激活到竞争状态。
            第四点:wait方法被调用的线程必须获得之前执行到wait时释放掉的锁重新获得才能够恢复执行。

    2  notify方法和notifyAll方法:
            notify方法通知调用了wait方法,但是尚未激活的一个线程进入线程调度队列(即进入锁竞争),注意不是立即执行。并且具体是哪一个线程不能保证。另外一点就是被唤醒的这个线程一定是在等待wait所释放的锁。
            notifyAll方法则唤醒所有调用了wait方法,尚未激活的进程进入竞争队列。

    3 synchronized关键字:
            第一点:synchronized用来标识一个普通方法时,表示一个线程要执行该方法,必须取得该方法所在的对象的锁
            第二点:synchronized用来标识一个静态方法时,表示一个线程要执行该方法,必须获得该方法所在的类的类锁
            第三点:synchronized修饰一个代码块。类似这样:synchronized(obj) { //code.... }。表示一个线程要执行该代码块,必须获得obj的锁。这样做的目的是减小锁的粒度,保证当不同块所需的锁不冲突时不用对整个对象加锁。利用零长度的byte数组对象做obj非常经济。

    4 atomic action(原子操作):
            在JAVA中,以下两点操作是原子操作。但是c和c++中并不如此。
            第一点:对引用变量和除了long和double之外的原始数据类型变量进行读写。
            第二点:对所有声明为volatile的变量(包括long和double)的读写。
            另外:在java.util.concurrent和java.util.concurrent.atomic包中提供了一些不依赖于同步机制的线程安全的类和方法。

     1 5 一个例子,该例子模仿多人存取同一个账户:
     2 Account类:
     3 package com.synchronize;
     4 
     5 import java.util.HashMap;
     6 import java.util.Iterator;
     7 
     8 public class Account {
     9     private static HashMap<String, Integer> m = new HashMap<String, Integer>();
    10     private static long times = 0;
    11     static {
    12         m.put("ren", 1000);
    13     }
    14 
    15     public synchronized void save(String name, int num) {
    16         long tempTime = times++;
    17         System.out.println("第 " + tempTime + " 次存储" + num + "之前" + name    + "的余额为:" + m.get(name));
    18         m.put(name, m.get(name) + num);
    19         this.notify();
    20         System.out.println("第 " + tempTime + " 次存储" + num + "之后" + name + "的余额为:" + m.get(name));
    21     }
    22 
    23     public static int get(String name) {
    24         return m.get(name);
    25     }
    26 
    27     /**
    28      * 注意wait的用法,必须在loop中,必须在拥有锁的代码块中。 前者是当被notify的时候要重新进行条件判断,后者是为了释放锁。
    29      * 
    30      * @param name
    31      * @param num
    32      */
    33     public synchronized void load(String name, int num) {
    34         long tempTime = times++;
    35         System.out.println("第 " + tempTime + " 次提取" + num + "之前" + name + "的余额为:" + m.get(name));
    36 
    37         try {
    38             while (m.get(name) < num) {
    39                 System.out.println("第 " + tempTime + " 次提取" + "余额" + m.get(name) + "不足,开始等待wait。");
    40                 this.wait();
    41                 System.out.println("第 " + tempTime + " 次提取操作被唤醒");
    42             }
    43         } catch (InterruptedException e) {
    44             // TODO Auto-generated catch block
    45             e.printStackTrace();
    46         }
    47         m.put(name, m.get(name) - num);
    48         System.out.println("第 " + tempTime + " 次提取" + num + "之后" + name + "的余额为:" + m.get(name));
    49     }
    50 }
    51 
    52 
    53 User类:
    54 package com.synchronize;
    55 
    56 /**
    57  * 这里注意runnable接口的线程是怎么实例化的。new Thread(new User())
    58  * 这里成功展示了多个用户存取同一个账户的多线程实例,通过多线程同步,保证了安全的执行。
    59  * @author abc
    60  * 
    61  */
    62 public class User implements Runnable {
    63     private static Account account = new Account();
    64     private final int id;
    65     
    66     User(int i){
    67         id=i;
    68     }
    69     
    70     public void run() {
    71         int tempMoney = 100;
    72         account.load("ren", tempMoney);
    73         try {
    74             Thread.sleep(3000);
    75         } catch (InterruptedException e) {
    76             // TODO Auto-generated catch block
    77             e.printStackTrace();
    78         }
    79         account.save("ren", 100);
    80         System.out.println("线程"+id+"完毕========================================================");
    81     }
    82 
    83     public static void main(String[] args) {
    84         for (int i = 0; i < 100; i++) {
    85             new Thread(new User(i)).start();
    86         }
    87     }
    88 }
    89 
    90 后续:请额外关注 ThreadLocal、JDK 5 中增加的 Lock 接口。
    91 参考资料:
    92 1  JDK Document
    93 2  http://java.sun.com/docs/books/tutorial/essential/concurrency/locksync.html
    94 3  http://java.sun.com/docs/books/tutorial/essential/concurrency/atomic.html
  • 相关阅读:
    对单片机程序中.data、.bss和.text三种数据的解读
    单片机驱动-软件模拟SPI
    MKL25-Low-Power Timer (LPTMR)
    使用intellij idea 查看Java字节码
    2.1 并发编程之java内存模型JMM & synchronize & volatile详解
    1.操作系统底层工作的基本原理
    JDBC(1)-数据库连接和CRUD操作
    Java反射详解
    Java Web(5)-Servlet详解(下)
    Java Web(5)-Servlet详解(上)
  • 原文地址:https://www.cnblogs.com/yaowukonga/p/3767559.html
Copyright © 2011-2022 走看看