多线程的同步
多线程同步控制机制的目的是保证同一时刻只有一个线程访问共享数据。java中,要实现多线程的同步,可使用同步方法和同步代码块两种机制。
1. 同步方法
使用synchronized修饰的方法称为同步方法,它意味着同一时刻该方法只能被一个线程执行,其它想执行该方法的线程必须等待(处于不可运行状态),直到获得同步锁之后才能执行(处于可运行状态)。
public synchronized void test() {
// 代码段
}
注(同步锁在哪儿):
(1)如果synchronized修饰的是实例方法,那么锁对象就是this。即,多个并发线程实际上是在实例方法所属的对象上加锁和获取锁。加锁和释放锁的过程由java虚拟机自动完成。
(2)如果synchronized修饰的是类中的静态方法,那么锁对象就是该类的Class实例。
(3)如果类中有多个synchronized方法:只要一个线程访问了其中一个synchronized方法,那么其它线程便不能同
时执行任何其它synchronized方法。当然,不同的对象实例中的synchronized方法是互不影响。也就是说,其
它线程可以同时访问另一个对象实例中的synchronized方法 。
(4)同步方法应尽可能小,即,同步方法中尽量只包含涉及共享资源的访问代码。其它不涉及共享资源的代码不必放入同步方法中,以提高线程的并发性。如果将run()方法修饰为synchronized,则线程并发性最差。
2. 同步代码块
创建一个用作同步锁的对象:
Object lock = new Object();
public void test1() {
synchronized (lock) { //在对象上加锁、或从对象上获取锁
// 代码段
}
}
注:
(1)务必保证使用同一个对象作为同步锁对象。
(2)如果一个线程得到了锁并进入了休眠状态(sleep),它仍然不会释放锁,直至同步块中的所有代码执行完毕。
多线程的同步与协作——生产者消费者问题
多个生产者(线程)给一个容器中放入产品(数据),多个消费者(线程)从容器中获取产品进行消费。容器放满后,生产者需要等待;容器为空时,消费者需要等待。生产者和消费者不能同时访问容器(互斥操作)。
此问题不仅有共享变量的互斥访问,而且还存在协作工作的问题。
import java.util.LinkedList;
import java.util.List;
public class Test2 {
public static final int MAX_SIZE = 10;
public static void main(String[] args) {
// Auto-generated method stub
List<String> container = new LinkedList<String>();
Producer p1 = new Producer(container, "p1");
Producer p2 = new Producer(container, "p2");
Producer p3 = new Producer(container, "p3");
Producer p4 = new Producer(container, "p4");
Consumer c1 = new Consumer(container, "c1");
Consumer c2 = new Consumer(container, "c2");
Consumer c3 = new Consumer(container, "c3");
p1.start();
p2.start();
p3.start();
p4.start();
c1.start();
c2.start();
c3.start();
}
}
class Producer extends Thread {
private List<String> container = null;
public Producer(List<String> con, String name) {
super(name);
this.container = con;
}
@Override
public void run() {
// 生产者
int i = 0;
String product = null;
while (i < 20) {
i++;
product = Thread.currentThread().getName() + ":" + i;
synchronized (container) {
while (container.size() >= Test2.MAX_SIZE) {
try {
container.wait();
} catch (InterruptedException e) {
}
}
container.add(product);
container.notifyAll();
}
// 释放锁
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
}
class Consumer extends Thread {
private List<String> container = null;
public Consumer(List<String> con, String name) {
super(name);
this.container = con;
}
@Override
public void run() {
// 消费者
String prd = null;
while (true) {
synchronized (container) {
while (container.size() == 0) {
try {
container.wait();
} catch (InterruptedException e) {
}
}
prd = container.remove(0);
container.notifyAll();
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName()+"消费了产品:"+prd);
}
}
}