线程-锁3

1、线程接力

案例:第一个线程打印5次,第二个线程打印10次,第三个线程打印15次,第三个线程执行完毕后,

再从第一个线程继续打印,执行第2轮的操作,总共执行10轮

线程接力代码

package com.thread.lock.test;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class TestCondition {
    Lock lock = new ReentrantLock();
    Condition con1 = lock.newCondition();
    Condition con2 = lock.newCondition();
    Condition con3 = lock.newCondition();
    private int flg = 1;

    public void product1(int j) {
        lock.lock();
        try {
            while (flg != 1) {
                try {
                    con1.await();
                } catch (InterruptedException e) {
                }
            }
            con2.signal();
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + "---" + i + "第" + j + "轮");
            }
            flg = 2;
        } finally {
            lock.unlock();
        }
    }

    public void product2(int j) {
        lock.lock();
        try {
            while (flg != 2) {
                try {
                    con2.await();
                } catch (InterruptedException e) {
                }
            }
            con3.signal();
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + "---" + i + "第" + j + "轮");
            }

            flg = 3;
        } finally {
            lock.unlock();
        }
    }

    public void product3(int j) {
        lock.lock();
        try {
            while (flg != 3) {
                try {
                    con3.await();
                } catch (InterruptedException e) {


                }
            }
            flg = 1;
            con1.signal();
            for (int i = 0; i < 15; i++) {
                System.out.println(Thread.currentThread().getName() + "---" + i + "第" + j + "轮");
            }


        } finally {
            lock.unlock();
        }
    }
}

public class LockConditionTest {
    public static void main(String[] args) {
        TestCondition ts = new TestCondition();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                ts.product1(i + 1);
            }
        }, "第一个线程").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                ts.product2(i + 1);
            }
        }, "第er个线程").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                ts.product3(i + 1);
            }
        }, "第san个线程").start();
    }


}

在上面的线程接力上用到了java.util.concurrent.locks.Lock、ReentrantLock、Condition

Lock和Synchronized之间的区别:

1、Synchronized是java关键字,给对象加锁,而且这个锁是我们不能控制的(jvm加锁),而lock是juc中提供的接口(他的实现ReentrantLock),由于是用户自己创建出来的锁,所以这个用户是可以控制的。

2、synchronized加锁后,必须获取监听器才可以执行,且他加锁后,是无法中断的,但是lock是可以中断的。

3、Synchronized释放锁是有顺序的,先加的锁后释放,而lock没有这个限制,可以随时的释放锁。

4、lock在使用时,是不可以在使用wait,notify,notifyAll方法,否则会报错的,他使用到了Condition的方法来代替了这几个方法,分别是await、signal、signalAll

 

2、案例:多个线程访问缓存,如果缓存中没有,读取数据库,如果有,直接获取。

可以参考一下思想来实现:

class CachedData {
   Object data;
   volatile boolean cacheValid;
   final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();


   void processCachedData() {
     rwl.readLock().lock();
     if (!cacheValid) {
       // Must release read lock before acquiring write lock
       rwl.readLock().unlock();
       rwl.writeLock().lock();
       try {
         // Recheck state because another thread might have
         // acquired write lock and changed state before we did.
         if (!cacheValid) {
           data = ...
           cacheValid = true;
         }
         // Downgrade by acquiring read lock before releasing write lock
         rwl.readLock().lock();
       } finally {
         rwl.writeLock().unlock(); // Unlock write, still hold read
       }
     }


     try {
       use(data);
     } finally {
       rwl.readLock().unlock();
     }
   }
 }}
//ReentrantReadWriteLocks can be used to improve concurrency in some uses of some kinds of Collections. This is typically worthwhile only //when the collections are expected to be large, accessed by more reader threads than writer threads, and entail operations with overhead that //outweighs synchronization overhead. For example, here is a class using a TreeMap that is expected to be large and concurrently accessed. 
 
 class RWDictionary {
   private final Map m = new TreeMap();
   private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
   private final Lock r = rwl.readLock();
   private final Lock w = rwl.writeLock();


   public Data get(String key) {
     r.lock();
     try { return m.get(key); }
     finally { r.unlock(); }
   }
   public String[] allKeys() {
     r.lock();
     try { return m.keySet().toArray(); }
     finally { r.unlock(); }
   }
   public Data put(String key, Data value) {
     w.lock();
     try { return m.put(key, value); }
     finally { w.unlock(); }
   }
   public void clear() {
     w.lock();
     try { m.clear(); }
     finally { w.unlock(); }
   }
 }}

这里使用ReadWriteLock读写锁来实现这个功能

 

这个锁也是由我们随意控制的。案例:100个线程读取,1个线程写入

class RedSpider1 {
    private String data = "";
    private ReadWriteLock lock = new ReentrantReadWriteLock();

    public void write(String data) {
        lock.writeLock().lock();

        try {
            this.data = data;
            System.out.println("教师端输入数据 = " + data);
        } finally {
            lock.writeLock().unlock();
        }
    }

    public String read() {
        lock.readLock().lock();
        try {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("学生端" + Thread.currentThread().getName() + "读取数据 = " + data);
            return data;
        } finally {
            lock.readLock().unlock();
        }
    }
}

public class TestJUC_05_rw_lock {


    public static void main(String[] args) throws Exception {
        final RedSpider1 rs = new RedSpider1();
// 多个线程的读取不需要加锁。
// 一个线程写数据的时候不能被其他线程读取,应该增加锁。
// 多个线程同时写入数据,也应该加锁。
        for (int i = 0; i < 100; i++) {
            new Thread(new Runnable() {
                public void run() {
                    rs.read();
                }
            }, "" + i).start();
        }

        Thread.sleep(100);

        new Thread(new Runnable() {
            public void run() {
                rs.write("java juc...");
            }
        }).start();

    }


}

        synchronized是关键字,他在加锁后是不能被打断的,因为他是系统加的锁机制(jvm),用户是控制不了。而ReetrantLock是Lock接口的实现类,这个类是可以在加锁后,是可以打断的,是受自己控制的,比较灵活,synchronized和ReentrantLock的区别

而ReetrantLock是不能和wait、notify、notifyAll这些搭配使用的,他一般的用Codition这额条件类的方法的await来替代Object类的wait,用signal来替代notify的,signalAll来替代notifyAll,Lock lock=new ReetrantLock();

Condition c=lock.newCondition();

这个ReetrantLock是一定要自己关闭的,而synchronized是不要我们自己去关闭的,

Synchronized释放锁的顺序是先加的后释放,而ReetrantLock释放锁比较灵活,可以自己定义

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
在Python中,线程是一种用于保护共享资源的同步机制,可以确保同一时刻只有一个线程访问共享资源,避免多个线程同时修改数据而导致数据不一致的问题。下面是一个使用线程的示例: ```python import threading # 定义一个共享资源,初始值为0 shared_resource = 0 # 定义一个线程 lock = threading.Lock() # 定义一个线程函数,用于修改共享资源的值 def update_shared_resource(): global shared_resource # 获取线程 lock.acquire() # 修改共享资源的值 shared_resource += 1 # 释放线程 lock.release() # 创建多个线程,同时访问共享资源 threads = [] for i in range(10): thread = threading.Thread(target=update_shared_resource) threads.append(thread) # 启动多个线程 for thread in threads: thread.start() # 等待所有线程执行完毕 for thread in threads: thread.join() # 输出共享资源的最终值 print("Shared resource: ", shared_resource) ``` 在上面的示例中,定义了一个共享资源`shared_resource`和一个线程`lock`。在`update_shared_resource()`函数中,先获取线程,然后修改共享资源的值,最后释放线程。在创建多个线程时,每个线程都会调用`update_shared_resource()`函数来修改共享资源的值,但是由于使用了线程,每次只有一个线程能够获得线程并修改共享资源的值,其他线程需要等待线程释放才能继续执行。 注意,获取线程后,需要在适当的时候释放线程,否则会导致死等问题。在上面的示例中,使用了`lock.acquire()`获取线程,并在`lock.release()`处释放线程

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值