苹果5多少钱现在市场价:JAVA多线程同步wait、notify、synchronized/

来源:百度文库 编辑:九乡新闻网 时间:2024/04/30 07:51:14

 

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 m = new HashMap();
    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();
        }
    }

 6、下面是自己写的,一个经典的消费者和生产者的例子:1、ObjLock.java /**
 * 生产者(producer)与消费者(consumer)问题
 * 说明事物锁与多线程同步
 * 生产者生产,消费者消费,规则:但当库存为0时,消费者要消费是不行的;
 * 但当库存为上限(这里是10)时,生产者也不能生产
 * @author wsq198753@qq.com
 */
public class ObjLock implements Runnable { private int count = 0;   //产品数
 
 private int locknum = 0; //上锁的线程数
 
 public ObjLock(int n){
  this.count = n;
 }
 
 //生产
 public synchronized void produce(){
  while(count == 10){
   locknum ++;
   try {
    wait();
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
  count ++;
  if(locknum > 0)
   locknum --;
  notify();
 }
 
 //消费
 public synchronized void consume(){
  while(count == 0){
   locknum ++;
   try {
    wait();
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
  count --;
  if(locknum > 0)
   locknum --;
  notify();
 }
 
 public void run() {
  while(true){
   if(Thread.currentThread().getName().substring(0, 8).equals("producer"))
    produce();
   else if(Thread.currentThread().getName().substring(0, 8).equals("consumer"))
    consume();
   System.out.println(Thread.currentThread().getName() + ": " + count + " ,locknum: " + locknum);
  }
 }}
2、TestObjLock测试类
public static void main(String[] args) {
  ObjLock ol = new ObjLock(1);
  Thread th1 = new Thread(ol,"producer");
  Thread th2 = new Thread(ol,"consumer");
  Thread th3 = new Thread(ol,"producer");
  Thread th4 = new Thread(ol,"consumer");
  Thread th5 = new Thread(ol,"producer");
  Thread th6 = new Thread(ol,"consumer");
  
  th1.start();
  th2.start();
  th3.start();
  th4.start();
  th5.start();
  th6.start();
 } 注意:这里所以生产和消费都必须有notify(),避免死锁。不信的可以去掉其中一个,可以测试实现。我记得大学学数据库的时候,也有说到这类问题。