关于多线程操作,我相信大家都不陌生,如何开启一个线程之类我想就不用太详细的去描述,今天我们就来讲讲线程同步的安全的问题。
对于线程同步安全问题,一般是一个多线程对同一个资源同时操作的时候,会出现资源同时操作造成线程不安全的问题。那么这个时候我们需要去对公共资源进行同步保护。这个时候有三种情况
1、同步代码块,这个同步的锁是任意一个对象;
2、方法同步,这个同步的锁就是该方法所在的类;
3、静态方法同步,这个同步的锁是该方法所在类的字节码。
接下来,我们举一个例子来说明多线程对同一个资源进行操作的时候,如何达到资源同步安全的问题。我们以生产消费的例子,生产一个商品,消费一个商品的循环。同时讲解线程同步中线程等待和唤醒的用法。
请看代码:
public class ThreadTest {
public static void main(String[] args) {
// 资源
Resources r = new Resources();
// 生产工厂
Producer pro = new Producer(r);
// 消费者
Consumer con = new Consumer(r);
// 四个线程同时进行生产和消费,实现生产一个消费一个,避免出现对资源的重复混乱应用
Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
public static class Resources {
public Resources() {
};
// 产品名称
private String name;
// 产品序号
private int count = 1;
// 循环标记位
private boolean flag = false;
// 生产方法
public synchronized void produce(String name) {
// 循环标记位
while (flag) {
try {
this.wait();
} catch (Exception e) {
}
}
// 生产出一个产品
this.name = name + "--" + count++;
System.out.println(Thread.currentThread().getName() + "制造一个商品"
+ this.name);
// 标记位转换,进入循环
flag = true;
// 为避免唤醒的线程队列中的第一个线程不是消费线程,我们选择全部唤醒
this.notifyAll();
}
// 消费方法
public synchronized void consume() {
while (!flag) {
try {
this.wait();
} catch (Exception e) {
}
}
System.out.println(Thread.currentThread().getName() + "消耗一个商品"
+ this.name);
// 标记位转换,进入循环
flag = false;
// 为避免唤醒的线程队列中的第一个线程不是生产线程,我们选择全部唤醒
this.notifyAll();
}
}
// 生产者
static class Producer implements Runnable {
private Resources res;
Producer(Resources res) {
this.res = res;
}
public void run() {
while (true) {
res.produce("商品");
}
}
}
// 消费者
static class Consumer implements Runnable {
private Resources res;
Consumer(Resources res) {
this.res = res;
}
public void run() {
while (true) {
res.consume();
}
}
}
}
我们发现,在上述过程中,我们会唤醒所有的等待线程,然后在根据循环标示为去控制生产与消费。这样总给是非常不好的感觉。当线程多的时候,会造成线程浪费。在JDK5.0之后,提供了线程同步锁Lock类来解决这一个问题。使用Lock类可以替代同步关键字来达到对公共资源的保护。我看直接看代码:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadTest2 {
public static void main(String[] args) {
Resource r = new Resource();
Producer pro = new Producer(r);
Consumer con = new Consumer(r);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
static class Resource {
// 新建一个锁
private Lock lock = new ReentrantLock();
private String name;
private int count = 1;
private boolean flag = false;
// 拿到对应的唤醒条件
private Condition proCondition = lock.newCondition();
private Condition conCondition = lock.newCondition();
public void product(String name) {
// 上锁
lock.lock();
try {
while (flag) {
// 等待
proCondition.await();
}
this.name = name + "--" + count++;
System.out.println(Thread.currentThread().getName() + "生产者"
+ this.name);
flag = true;
// 唤醒消费线程
conCondition.signal();
} catch (Exception e) {
} finally {
// 解锁
lock.unlock();
}
}
public void consume() {
// 上锁
lock.lock();
try {
while (!flag) {
conCondition.wait();
}
System.out.println(Thread.currentThread().getName() + "消费者----"
+ this.name);
flag = false;
// 唤醒生产者
proCondition.signal();
} catch (Exception e) {
} finally {
// 解锁
lock.unlock();
}
}
}
static class Producer implements Runnable {
private Resource res;
Producer(Resource res) {
this.res = res;
}
public void run() {
while (true) {
res.product("商品");
}
}
}
static class Consumer implements Runnable {
private Resource res;
Consumer(Resource res) {
this.res = res;
}
public void run() {
while (true) {
res.consume();
}
}
}
}
以上就是线程同步安全的内容。
原文地址:http://blog.csdn.net/victorfreedom/article/details/43172027