关于多线程操作,我相信大家都不陌生,如何开启一个线程之类我想就不用太详细的去描述,今天我们就来讲讲线程同步的安全的问题。
对于线程同步安全问题,一般是一个多线程对同一个资源同时操作的时候,会出现资源同时操作造成线程不安全的问题。那么这个时候我们需要去对公共资源进行同步保护。这个时候有三种情况
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(); } } } }
关于Lock类的更多使用方法大家可以参照JDK文档。
以上就是线程同步安全的内容。
时间: 2024-10-03 22:40:01