`

Java synchronized线程同步锁及线程间通过对象的wait,notify进行交互

 
阅读更多
1.synchronized关键字
    synchronized是用来控制线程的并发执行的,它只能作用于一个方法或者一个代码块上,通过它能保证一段代码或一个方法有多个线程调用时能顺序执行。
    工作机制:
    当程序运行到非静态的synchronized同步方法上时,自动获得与正在执行代码类的当前实例(this实例)有关的锁。获得一个对象的锁也称为获取锁、锁定对象、在对象上锁定或在对象上同步。
    当程序运行到synchronized同步方法或代码块时才该对象锁才起作用。一个对象只有一个锁。所以,如果一个线程获得该锁,就没有其他线程可以获得锁,直到第一个线程释放(或返回)锁。这也意味着任何其他线程都不能进入该对象上的synchronized方法或代码块,直到该锁被释放。释放锁是指持锁线程退出了synchronized同步方法或代码块。
示例代码:
package com.ajita;

public class TestSynchronized {

	class Account {
		private int total = 0;

		public synchronized void add(int n) {
			total = total + n;
		}

		public synchronized void minus(int n) {
			total = total - n;
		}

		public int getTotal() {
			return total;
		}
	}

	class AddThread extends Thread {
		private Account acct;
		private int addCount = 0;

		AddThread(String name, Account acct, int addNum) {
			super(name);
			this.acct = acct;
			this.addCount = addNum;
		}

		public void run() {
			for (int i = 0; i < addCount; i++) {
				acct.add(1);
				System.out.println(this.getName() + acct.getTotal());
				try {
					Thread.sleep(11);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

	class MinusThread extends Thread {
		private Account acct;
		private int minusNum = 0;

		MinusThread(String name, Account acct, int minusNum) {
			super(name);
			this.acct = acct;
			this.minusNum = minusNum;
		}

		public void run() {
			for (int i = 0; i < minusNum; i++) {
				acct.minus(1);
				System.out.println(this.getName() + acct.getTotal());
				try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

	public void test() {
		Account a = new Account();
		System.out.println(a.getTotal());
		Thread addThread = new AddThread("add", a, 50);
		Thread minusThread = new MinusThread("minus", a, 50);
		addThread.start();
		minusThread.start();
		try {
			addThread.join();
			minusThread.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(a.getTotal());
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		TestSynchronized test = new TestSynchronized();
		test.test();
	}
}


使用synchronized锁,可能造成死锁的问题。最典型的是线程1先锁A,再来锁B,线程2先锁B,再来锁A,如下代码:
package com.ajita;

public class TestDeadLock {
	public class DeadlockRisk {

		private Object resourceA = new Object();
		private Object resourceB = new Object();

		public void lockAFirst() {
			synchronized (resourceA) {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				synchronized (resourceB) {
					System.out.println("lockAFirst get Locked");
				}
			}
		}

		public void lockBFirst() {
			synchronized (resourceB) {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				synchronized (resourceA) {
					System.out.println("lockBFirst get Locked");
				}
			}
		}
	}

	class LockAFirstThread extends Thread {
		public DeadlockRisk deadLock;

		public void run() {
			deadLock.lockAFirst();
		}
	}

	class LockBFirstThread extends Thread {
		public DeadlockRisk deadLock;

		public void run() {
			deadLock.lockBFirst();
		}
	}

	public void test() {
		DeadlockRisk lock = new DeadlockRisk();
		LockAFirstThread a = new LockAFirstThread();
		a.deadLock = lock;
		LockBFirstThread b = new LockBFirstThread();
		b.deadLock = lock;
		a.start();
		b.start();
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		TestDeadLock test = new TestDeadLock();
		test.test();
	}
}


2.wait,notify,notifyAll
    任意Java对象都有如下3个方法,不同线程之间可以利用同一个对象的这三个方法进行通信。
    关于等待/通知,要记住的关键点是:
必须从同步环境内(就是synchronized 代码块内)调用wait()、notify()、notifyAll()方法。线程不能调用对象上等待或通知的方法,除非它拥有那个对象的锁。
void notify()
          唤醒在此对象监视器上等待的单个线程。 有重载的。
void notifyAll()
          唤醒在此对象监视器上等待的所有线程。
void wait()
          导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。
    最经典的例子就是生产者,消费者的例子。
代码如下,百度来的
package com.ajita;

/**
 * Java线程:并发协作-生产者消费者模型
 * 
 * @author leizhimin 2009-11-4 14:54:36
 */
public class ProducerAndConsumer {
	public static void main(String[] args) {
		Godown godown = new Godown(30);
		Consumer c1 = new Consumer(50, godown);
		Consumer c2 = new Consumer(20, godown);
		Consumer c3 = new Consumer(30, godown);
		Producer p1 = new Producer(10, godown);
		Producer p2 = new Producer(10, godown);
		Producer p3 = new Producer(10, godown);
		Producer p4 = new Producer(10, godown);
		Producer p5 = new Producer(10, godown);
		Producer p6 = new Producer(10, godown);
		Producer p7 = new Producer(80, godown);

		c1.start();
		c2.start();
		c3.start();
		p1.start();
		p2.start();
		p3.start();
		p4.start();
		p5.start();
		p6.start();
		p7.start();
	}
}

/**
 * 仓库
 */
class Godown {
	public static final int max_size = 100; // 最大库存量
	public int curnum; // 当前库存量

	Godown() {
	}

	Godown(int curnum) {
		this.curnum = curnum;
	}

	/**
	 * 生产指定数量的产品
	 * 
	 * @param neednum
	 */
	public synchronized void produce(int neednum) {
		// 测试是否需要生产
		while (neednum + curnum > max_size) {
			System.out.println("要生产的产品数量" + neednum + "超过剩余库存量"
					+ (max_size - curnum) + ",暂时不能执行生产任务!");
			try {
				// 当前的生产线程等待
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		// 满足生产条件,则进行生产,这里简单的更改当前库存量
		curnum += neednum;
		System.out.println("已经生产了" + neednum + "个产品,现仓储量为" + curnum);
		// 唤醒在此对象监视器上等待的所有线程
		notifyAll();
	}

	/**
	 * 消费指定数量的产品
	 * 
	 * @param neednum
	 */
	public synchronized void consume(int neednum) {
		// 测试是否可消费
		while (curnum < neednum) {
			try {
				// 当前的生产线程等待
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		// 满足消费条件,则进行消费,这里简单的更改当前库存量
		curnum -= neednum;
		System.out.println("已经消费了" + neednum + "个产品,现仓储量为" + curnum);
		// 唤醒在此对象监视器上等待的所有线程
		notifyAll();
	}
}

/**
 * 生产者
 */
class Producer extends Thread {
	private int neednum; // 生产产品的数量
	private Godown godown; // 仓库

	Producer(int neednum, Godown godown) {
		this.neednum = neednum;
		this.godown = godown;
	}

	public void run() {
		// 生产指定数量的产品
		godown.produce(neednum);
	}
}

/**
 * 消费者
 */
class Consumer extends Thread {
	private int neednum; // 生产产品的数量
	private Godown godown; // 仓库

	Consumer(int neednum, Godown godown) {
		this.neednum = neednum;
		this.godown = godown;
	}

	public void run() {
		// 消费指定数量的产品
		godown.consume(neednum);
	}
}

    本例仅仅是生产者消费者模型中最简单的一种表示,本例中,如果消费者消费的仓储量达不到满足,而又没有生产者,则程序会一直处于等待状态,这当然是不对的。实际上可以将此例进行修改,修改为,根据消费驱动生产,同时生产兼顾仓库,如果仓不满就生产,并对每次最大消费量做个限制,这样就不存在此问题了,当然这样的例子更复杂,更难以说明这样一个简单模型。
分享到:
评论

相关推荐

    基于Java synchronized同步锁实现线程交互.pdf

    Java synchronized同步锁可以保证同一时刻只有一个线程操作同一资源,使用wait()、notify()切换线程状态保证线程操作的前后顺序实现线程交互。 Java线程状态有五种:新建状态、就绪状态、运行状态、休眠状态和死亡...

    Java 同步锁 wait notify 学习心得

    标题和描述概述的知识点主要集中在Java的多线程机制中,特别是`wait`和`notify`方法在同步锁中的应用。这些方法对于控制线程之间的交互至关重要,尤其是在资源有限或需要确保数据一致性的情况下。 ### Java同步锁...

    java 多线程交互简单范例

    Java提供了多种线程同步机制,如synchronized关键字、wait()和notify()方法、ReentrantLock等。 在给定的文件中,我们有以下几个文件: 1. **Producer.java**:这个文件可能包含一个生产者线程的实现,它的任务是...

    操作系统实验 多线程同步与互斥 java编写 有界面

    在“操作系统实验 多线程同步与互斥 java编写 有界面”的实验中,可能需要设计一个图形用户界面(GUI),通过按钮或事件触发线程的创建和同步操作,直观地展示线程间的交互和同步效果。例如,可以模拟银行账户转账,...

    java多线程经典案例

    Java中,可以通过wait()、notify()和notifyAll()这三个Object类的方法来实现线程间的通信。这些方法必须在同步环境中使用,否则会抛出异常。此外,Java 5引入了BlockingQueue阻塞队列,它是一种线程安全的数据结构,...

    wait_notify_demo

    在Java中,`wait()`、`notify()`和`notifyAll()`方法都是与对象锁相关的,它们用于控制线程的同步。使用这些方法的前提是线程必须拥有对象的监视器,也就是对象锁。这是通过在synchronized块或方法中调用它们来实现...

    java线程线程安全同步线程

    `wait()`和`notify()`/`notifyAll()`方法用于线程间的通信,使得线程可以在特定条件下释放资源并等待其他线程唤醒;`ReentrantLock`可重入锁提供了更灵活的控制,支持公平锁和非公平锁策略。 线程优先级是调度的...

    Java分布式应用学习笔记03JVM对线程的资源同步和交互机制

    5. **线程间通信**:除了锁机制,JVM还提供了一系列的线程间通信工具,如`ThreadLocal`、`Wait/Notify`、`CountDownLatch`、`Semaphore`、`CyclicBarrier`等,用于解决线程间的同步问题,使多线程程序更加灵活和可控...

    java多线程进度条

    为了在多线程中同步进度更新,我们可以利用synchronized关键字、wait()、notify()方法,或者使用Java并发库中的高级工具,如Semaphore、CyclicBarrier或CountDownLatch等。 一个简单的进度条实现可以采用共享变量...

    JAVAJAVA多线程教学演示系统论文

    3. **线程同步与并发控制**:论文会深入讲解JAVA中的线程同步机制,如synchronized关键字、wait()、notify()和notifyAll()方法,以及Lock接口和ReentrantLock类的使用。此外,可能会探讨并发工具类,如Semaphore、...

    java多线程源码,仅供参考

    `wait()`和`notify()`是对象级别的锁控制,用于线程间的通信,一个线程调用`wait()`会释放当前持有的锁并等待,而其他线程调用`notify()`或`notifyAll()`可以唤醒等待的线程。 "BounceThread"这个示例可能涉及到...

    Java多线程编程经验

    Java提供了 `wait()`、`notify()` 和 `notifyAll()` 等方法来支持这种交互。 #### 八、Java线程:线程的调度 线程调度涉及到如何安排线程的执行顺序,包括但不限于: 1. **休眠**:使当前正在执行的线程暂停一段...

    Java线程同步例子.pdf

    在synchronized方法或代码块内部,可以通过调用wait()方法使当前线程放弃锁,并进入等待状态,直到其他线程调用notify()方法或notifyAll()方法。notify()方法唤醒在此对象监视器上等待的单个线程,而notifyAll()方法...

    Java多线程编程总结

    - 线程间的交互涉及到线程间的数据传递和同步操作,主要技术包括 `wait()`、`notify()`、`notifyAll()` 等方法,以及 `CountDownLatch`、`CyclicBarrier` 等类。 #### 七、Java线程:线程的调度 1. **休眠** - `...

    Java多线程教程资料(强烈推荐).docx

    Java 中的线程可以通过多种方式进行交互,如 wait() 和 notify() 方法、join() 方法、LockSupport 类等。wait() 方法可以用于线程等待某个条件的满足,而 notify() 方法可以用于通知其他线程某个条件的满足。join() ...

    Java多线程编程线程的协同、停止、暂停、继续等操作实现

    在Java中,线程的协同主要通过`wait()`和`notify()`或`notifyAll()`方法来实现,这些方法定义在`Object`类中。当一个线程调用`wait()`时,它会释放当前持有的锁并进入等待状态,直到其他线程调用`notify()`或`...

    java多线程编程总结

    Java提供了多种方式让线程间进行通信,如 `wait()`、`notify()` 和 `notifyAll()` 方法。这些方法用于实现线程之间的等待和通知机制。 #### 七、Java线程:线程的调度 - **线程的调度策略** 包括休眠、优先级...

    java多线程的应用事例

    在Java中,线程间通信是通过共享内存(变量)和同步机制(如synchronized关键字、wait/notify机制)来实现的。例如,如果这个示例是银行转账操作,那么两个线程分别代表不同的账户,它们需要在修改余额时进行同步,...

    java多线程并发实战和源码

    线程同步主要包括synchronized关键字、wait/notify机制、Lock锁(如ReentrantLock)以及Semaphore信号量等,它们用于避免竞态条件,确保共享资源的安全访问。 接着,我们来看Java内存模型(JMM),这是理解多线程...

Global site tag (gtag.js) - Google Analytics