转: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包中提供了一些不依赖于同步机制的线程安全的类和方法。

 5 一个例子,该例子模仿多人存取同一个账户:
Account类:
package com.synchronize; import java.util.HashMap;
import java.util.Iterator; public class Account {
private static HashMap<String, Integer> m = new HashMap<String, Integer>();
private static long times = 0;
static {
m.put("ren", 1000);
} public synchronized void save(String name, int num) {
long tempTime = times++;
System.out.println("第 " + tempTime + " 次存储" + num + "之前" + name + "的余额为:" + m.get(name));
m.put(name, m.get(name) + num);
this.notify();
System.out.println("第 " + tempTime + " 次存储" + num + "之后" + name + "的余额为:" + m.get(name));
} public static int get(String name) {
return m.get(name);
} /**
* 注意wait的用法,必须在loop中,必须在拥有锁的代码块中。 前者是当被notify的时候要重新进行条件判断,后者是为了释放锁。
*
* @param name
* @param num
*/
public synchronized void load(String name, int num) {
long tempTime = times++;
System.out.println("第 " + tempTime + " 次提取" + num + "之前" + name + "的余额为:" + m.get(name)); try {
while (m.get(name) < num) {
System.out.println("第 " + tempTime + " 次提取" + "余额" + m.get(name) + "不足,开始等待wait。");
this.wait();
System.out.println("第 " + tempTime + " 次提取操作被唤醒");
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
m.put(name, m.get(name) - num);
System.out.println("第 " + tempTime + " 次提取" + num + "之后" + name + "的余额为:" + m.get(name));
}
} User类:
package com.synchronize; /**
* 这里注意runnable接口的线程是怎么实例化的。new Thread(new User())
* 这里成功展示了多个用户存取同一个账户的多线程实例,通过多线程同步,保证了安全的执行。
* @author abc
*
*/
public class User implements Runnable {
private static Account account = new Account();
private final int id; User(int i){
id=i;
} public void run() {
int tempMoney = 100;
account.load("ren", tempMoney);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
account.save("ren", 100);
System.out.println("线程"+id+"完毕========================================================");
} public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(new User(i)).start();
}
}
} 后续:请额外关注 ThreadLocal、JDK 5 中增加的 Lock 接口。
参考资料:
1 JDK Document
2 http://java.sun.com/docs/books/tutorial/essential/concurrency/locksync.html
3 http://java.sun.com/docs/books/tutorial/essential/concurrency/atomic.html

转:关于JAVA多线程同步的更多相关文章

  1. Java多线程同步问题的探究

    一.线程的先来后到——问题的提出:为什么要有多线程同步?Java多线程同步的机制是什么? http://www.blogjava.net/zhangwei217245/archive/2010/03/ ...

  2. java多线程同步

    一篇好文:java多线程机制同步原则 概括起来说,Java 多线程同步机制主要包含如下几点:1:如果一个类包含一个或几个同步方法,那么由此类生成的每一个对象都配备一个队列用来容纳那些等待执行同步的线程 ...

  3. Java多线程-同步:synchronized 和线程通信:生产者消费者模式

    大家伙周末愉快,小乐又来给大家献上技术大餐.上次是说到了Java多线程的创建和状态|乐字节,接下来,我们再来接着说Java多线程-同步:synchronized 和线程通信:生产者消费者模式. 一.同 ...

  4. Java多线程同步 synchronized 关键字的使用

    代表这个方法加锁,相当于不管哪一个线程A每次运行到这个方法时,都要检查有没有其它正在用这个方法的线程B(或者C D等),有的话要等正在使用这个方法的线程B(或者C D)运行完这个方法后再运行此线程A, ...

  5. Java多线程---同步与锁

    一,线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏. 二.同步和锁定 1.锁的原理 Java中每个对象都有一个内置锁. 当程序运行到非静态的synchronized同步方法上时,自动 ...

  6. Java多线程同步的方法

    一 synchronized关键字 1.synchronized实现原理: ---基于对象监视器(锁) java中所有对象都自动含有单一的锁,JVM负责跟踪对象被加锁的次数.如果一个对象被解锁,其计数 ...

  7. Java 多线程同步的五种方法

    一.引言 闲话不多说,进入正题. 二.为什么要线程同步 因为当我们有多个线程要同时访问一个变量或对象时,如果这些线程中既有读又有写操作时,就会导致变量值或对象的状态出现混乱,从而导致程序异常.举个例子 ...

  8. Java多线程同步问题:一个小Demo完全搞懂

    版权声明:本文出自汪磊的博客,转载请务必注明出处. Java线程系列文章只是自己知识的总结梳理,都是最基础的玩意,已经掌握熟练的可以绕过. 一.一个简单的Demo引发的血案 关于线程同步问题我们从一个 ...

  9. java多线程同步(转)

    原文地址:http://developer.51cto.com/art/201509/490965.htm 一.场景 因为当我们有多个线程要同时访问一个变量或对象时,如果这些线程中既有读又有写操作时, ...

随机推荐

  1. c#获得目标服务器中所有数据库名、表名、列名的实现代码

    /// <summary> /// 获得目标服务器所有数据库名 /// </summary> /// <param name="serverName" ...

  2. IOS开发 xcode报错之has been modified since the precompiled header was built

    转载的文章  很实用 IOS开发xcode报错之has been modified since the precompiled header was built 今天做百度地图的时候第一次发现下面错误 ...

  3. 使用autolayout的NSLayoutConstraint类中的constraintWithItem 、constraintsWithVisualFormat这两个类方法来创建视图并可以实现自动布局

    #import "ViewController.h" @interface ViewController () @end @implementation ViewControlle ...

  4. 【Android 界面效果31】Android--侧滑菜单应用的实现

    侧滑菜单应用现在非常多,而且实现方式也多种多样.通过在网上的多方查找,我找到郭霖少侠的这篇文章:http://blog.csdn.net/guolin_blog/article/details/874 ...

  5. Strom实现数字累加Demo

    import java.util.Map; import backtype.storm.Config; import backtype.storm.LocalCluster; import backt ...

  6. 在centos中创建nginx启动脚本

    1. 建立脚本文件nginxd [root@could]# vi /etc/init.d/nginxd 插入以下内容 #!/bin/bash## chkconfig: - 85 15# descrip ...

  7. selenium遍历控件集合

    场景:需要重复增加地址栏信息,如果地址信息超过了5个就不开始增加 如图: 1.找到控件集合,在遍历每个子元素,在进行选择 1.先找到最外层的div的控件集合 2.外层的css定位为: int star ...

  8. highchairts柱状图显示数值并且带单位

    $(target).highcharts({ chart: { type: 'bar' }, colors: [ "#1ab394" ], title: { text: title ...

  9. VB.NET 小程序 3

    Public Class Form1 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click ...

  10. java初级开发中的报错问题

      1.典例1 错误原因:?useUnicode=true&characterEncoding=UTxF8 纠错:其中的? 是汉语的 2.典例2 纠错原因:数据库没有打开 纠错: 我的电脑-- ...