@@ -231,6 +231,14 @@ executor提供一个原生函数isTerminated()来判断线程池中的任务是
231231- 调用new Thread()创建的线程缺乏管理,可以无限制的创建,线程之间的相互竞争会导致过多占用系统资源而导致系统瘫痪
232232- 直接使用new Thread()启动的线程不利于扩展,比如定时执行、定期执行、定时定期执行、线程中断等都不好实现
233233
234+ ## execute和submit的区别
235+
236+ execute只能提交Runnable类型的任务,无返回值。submit既可以提交Runnable类型的任务,也可以提交Callable类型的任务,会有一个类型为Future的返回值,但当任务类型为Runnable时,返回值为null。
237+
238+ execute在执行任务时,如果遇到异常会直接抛出,而submit不会直接抛出,只有在使用Future的get方法获取返回值时,才会抛出异常
239+
240+ execute所属顶层接口是Executor,submit所属顶层接口是ExecutorService,实现类ThreadPoolExecutor重写了execute方法,抽象类AbstractExecutorService重写了submit方法。
241+
234242## 进程线程
235243
236244进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间。
@@ -1238,4 +1246,115 @@ epoll的时间复杂度O(1)。epoll可以理解为event poll,不同于忙轮
12381246
12391247> 参考链接:https://blog.csdn.net/u014209205/article/details/80598209
12401248
1249+ ## ReadWriteLock 和 StampedLock 的区别
1250+
1251+ 在多线程编程中,对于共享资源的访问控制是一个非常重要的问题。在并发环境下,多个线程同时访问共享资源可能会导致数据不一致的问题,因此需要一种机制来保证数据的一致性和并发性。
1252+
1253+ Java提供了多种机制来实现并发控制,其中 ReadWriteLock 和 StampedLock 是两个常用的锁类。本文将分别介绍这两个类的特性、使用场景以及示例代码。
1254+
1255+ ** ReadWriteLock**
1256+
1257+ ReadWriteLock 是Java提供的一个接口,全类名:` java.util.concurrent.locks.ReentrantLock ` 。它允许多个线程同时读取共享资源,但只允许一个线程写入共享资源。这种机制可以提高读取操作的并发性,但写入操作需要独占资源。
1258+
1259+ ** 特性**
1260+
1261+ - 多个线程可以同时获取读锁,但只有一个线程可以获取写锁。
1262+ - 当一个线程持有写锁时,其他线程无法获取读锁和写锁,读写互斥。
1263+ - 当一个线程持有读锁时,其他线程可以同时获取读锁,读读共享。
1264+
1265+ ** 使用场景**
1266+
1267+ ** ReadWriteLock** 适用于读多写少的场景,例如缓存系统、数据库连接池等。在这些场景中,读取操作占据大部分时间,而写入操作较少。
1268+
1269+ ** 示例代码**
1270+
1271+ 下面是一个使用 ReadWriteLock 的示例,实现了一个简单的缓存系统:
1272+
1273+ ``` java
1274+ public class Cache {
1275+ private Map<String , Object > data = new HashMap<> ();
1276+ private ReadWriteLock lock = new ReentrantReadWriteLock ();
1277+
1278+ public Object get (String key ) {
1279+ lock. readLock(). lock();
1280+ try {
1281+ return data. get(key);
1282+ } finally {
1283+ lock. readLock(). unlock();
1284+ }
1285+ }
1286+
1287+ public void put (String key , Object value ) {
1288+ lock. writeLock(). lock();
1289+ try {
1290+ data. put(key, value);
1291+ } finally {
1292+ lock. writeLock(). unlock();
1293+ }
1294+ }
1295+ }
1296+ ```
1297+
1298+ 在上述示例中,Cache 类使用 ReadWriteLock 来实现对 data 的并发访问控制。get 方法获取读锁并读取数据,put 方法获取写锁并写入数据。
1299+
1300+ ** StampedLock**
1301+
1302+ StampedLock 是Java 8 中引入的一种新的锁机制,全类名:` java.util.concurrent.locks.StampedLock ` ,它提供了一种乐观读的机制,可以进一步提升读取操作的并发性能。
1303+
1304+ ** 特性**
1305+
1306+ - 与 ReadWriteLock 类似,StampedLock 也支持多个线程同时获取读锁,但只允许一个线程获取写锁。
1307+ - 与 ReadWriteLock 不同的是,StampedLock 还提供了一个乐观读锁(Optimistic Read Lock),即不阻塞其他线程的写操作,但在读取完成后需要验证数据的一致性。
1308+
1309+ ** 使用场景**
1310+
1311+ StampedLock 适用于读远远大于写的场景,并且对数据的一致性要求不高,例如统计数据、监控系统等。
1312+
1313+ ** 示例代码**
1314+
1315+ 下面是一个使用 StampedLock 的示例,实现了一个计数器:
1316+
1317+ ``` java
1318+ public class Counter {
1319+ private int count = 0 ;
1320+ private StampedLock lock = new StampedLock ();
1321+
1322+ public int getCount () {
1323+ long stamp = lock. tryOptimisticRead();
1324+ int value = count;
1325+ if (! lock. validate(stamp)) {
1326+ stamp = lock. readLock();
1327+ try {
1328+ value = count;
1329+ } finally {
1330+ lock. unlockRead(stamp);
1331+ }
1332+ }
1333+ return value;
1334+ }
1335+
1336+ public void increment () {
1337+ long stamp = lock. writeLock();
1338+ try {
1339+ count++ ;
1340+ } finally {
1341+ lock. unlockWrite(stamp);
1342+ }
1343+ }
1344+ }
1345+ ```
1346+
1347+ 在上述示例中,Counter 类使用 StampedLock 来实现对计数器的并发访问控制。getCount 方法首先尝试获取乐观读锁,并读取计数器的值,然后通过 validate 方法验证数据的一致性。如果验证失败,则获取悲观读锁,并重新读取计数器的值。increment 方法获取写锁,并对计数器进行递增操作。
1348+
1349+ ** 总结**
1350+
1351+ ** ReadWriteLock** 和 ** StampedLock** 都是Java中用于并发控制的重要机制。
1352+
1353+ - ** ReadWriteLock** 适用于读多写少的场景;
1354+ - ** StampedLock** 则适用于读远远大于写的场景,并且对数据的一致性要求不高;
1355+
1356+ 在实际应用中,我们需要根据具体场景来选择合适的锁机制。通过合理使用这些锁机制,我们可以提高并发程序的性能和可靠性。
1357+
1358+
1359+
12411360![ ] ( http://img.topjavaer.cn/img/20220612101342.png )
0 commit comments