來吧,展示,從零開始學Java編程

程序員小秘境 2021-09-18 05:44:46 阅读数:956

展示 java
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
// 三個方法的使用方法和 wait,notify 和 notifyAll一樣

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

線程按序交替

編寫一個程序,開啟 3 個線程,這三個線程的 ID 分別為 A、B、C,每個線程將自己的 ID 在屏幕上打印 10 遍,要 求輸出的結果必須按順序顯示。 如:ABCABCABC…… 依次遞歸

public class ABCAlternateTest {
public static void main(String[] args) {
AlternateDemo ad = new AlternateDemo();
new Thread(new Runnable() {
@Override
public void run(){
for (int i = 1; i <= 10; i++) {
ad.loopA(i);
}
}
},"A").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
ad.loopB(i);
}
}
},"B").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
ad.loopC(i);
}
}
},"C").start();
}
}
class AlternateDemo {
// 記錄當前正在執行的線程的ID
private int number = 1;
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
public void loopA(int totalLoop) {
try {
lock.lock();
if(number != 1) {
try {
condition1.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 打印
for (int i = 1; i <= 1; i++) {
System.out.print(Thread.currentThread().getName());
}
number = 2;
condition2.signal();
} finally {
lock.unlock();
}
}
public void loopB(int totalLoop) {
try {
lock.lock();
if(number != 2) {
try {
condition2.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 打印
for (int i = 1; i <= 1; i++) {
System.out.print(Thread.currentThread().getName());
}
number = 3;
condition3.signal();
} finally {
lock.unlock();
}
}
public void loopC(int totalLoop) {
try {
lock.lock();
if(number != 3) {
try {
condition3.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 打印
for (int i = 1; i <= 1; i++) {
System.out.print(Thread.currentThread().getName());
}
number = 1;
condition1.signal();
System.out.print(" ");
} finally {
lock.unlock();
}
}
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.

ReadWriteLock 讀寫鎖

ReadWriteLock是一個接口

ReadWriteLock 維護了一對相關的鎖,一個用於只讀操作, 另一個用於寫入操作。只要沒有 writer,讀取鎖可以由?多個 reader?線程同時保持。寫入鎖是獨占的

ReadWriteLock 讀取操作通常不會改變共享資源,但執行 寫入操作時,必須獨占方式來獲取鎖。?對於讀取操作占 多數的數據結構。ReadWriteLock 能提供比獨占鎖更高 的並發性。而對於只讀的數據結構,其中包含的不變性 可以完全不需要考慮加鎖操作

  • 寫寫 / 讀寫 都需要“互斥”
  • 讀讀 不需要互斥
public class ReadWriteLockTest {
public static void main(String[] args) {
ReadWriteLockDemo rw = new ReadWriteLockDemo();
new Thread(new Runnable() {
@Override
public void run() {
rw.set((int)(Math.random() * 101));
}
},"write").start();
for (int i = 0; i < 100; i++) {
new Thread(new Runnable() {
@Override
public void run() {
rw.get();
}
}).start();
}
}
}
class ReadWriteLockDemo {
private int number = 0;
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 讀
public void get() {
try {
readWriteLock.readLock().lock();
System.out.println(Thread.currentThread().getName() + ":" + number);
} finally {
readWriteLock.readLock().unlock();
}
}
// 寫
public void set(int number) {
try {
readWriteLock.writeLock().lock();
System.out.println(Thread.currentThread().getName());
this.number = number;
} finally {
readWriteLock.writeLock().unlock();
}
}
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.

線程八鎖

靜態同步方法與非靜態同步方法之間是不會有競態條件的,非靜態同步方法,看他們的鎖是不是同一個number,是同一個number則,一個拿到,另一個要等待;否則,另一個不用等待

* 線程八鎖的關鍵: 1.非靜態方法的鎖 this, 靜態方法的鎖 對應的Class實例
* 2.某一個時刻內,只能由一個線程持有鎖,無論幾個方法
* 1.兩個同步方法,兩個線程,打印 one two
* 2.新增Thread.sleep()給getOne 打印 one two
* 3.新增普通方法getThree,打印 three one two
* 4.注釋getThree,number2.getTwo,打印 two one
* 5.修改getOne為靜態同步方法,改為number.getTwo,打印 two one
* 6.兩個方法都為靜態同步方法,一個number對象,打印 one two
* 7.getOne為靜態同步方法,getTwo為同步方法,改為number2.getTwo,打印two one
* 8.兩個靜態同步方法,兩個number對象,打印 one two
*/
public class Thread8MonitorTest {
public static void main(String[] args) {
Number number = new Number();
// 4
// Number number2 = new Number();
// 7
Number number2 = new Number();
new Thread(new Runnable() {
@Override
public void run() {
number.getOne();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
// 1,2,3
// number.getTwo();
// 4
// number2.getTwo();
// 5
// number.getTwo();
// 7
number2.getTwo();
}
}).start();
// 3
/*new Thread(new Runnable() {
@Override
public void run() {
number.getThree();
}
}).start();*/
}
}
class Number{
public static synchronized void getOne() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("one");
}
public static synchronized void getTwo() {
System.out.println("two");
}
public void getThree() {
System.out.println("three");
}
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.

線程池

第四種獲取線程的方法:線程池,一個 ExecutorService,它使用可能的幾個池線程之 一執行每個提交的任務,通常使用 Executors 工廠方法配置。

線程池可以解决兩個不同問題:由於减少了每個任務調用的開銷,它們通常可以在 執行大量异步任務時提供增强的性能,並且還可以提供綁定和管理資源(包括執行 任務集時使用的線程)的方法。每個 ThreadPoolExecutor 還維護著一些基本的統計數 據,如完成的任務數。

為了便於跨大量上下文使用,此類提供了很多可調整的參數和擴展鉤子 (hook)。但 是,强烈建議程序員使用較為方便的 Executors 工廠方法 :

  • Executors.newCachedThreadPool()(無界線程池,可以進行自動線程回收)
  • Executors.newFixedThreadPool(int)(固定大小線程池)
  • Executors.newSingleThreadExecutor()(單個後臺線程) 它們均為大多數使用場景預定義了設置。

思路:提前創建好多個線程,放入線程池中,使用時直接獲取,使用完 放回池中。可以避免頻繁創建銷毀、實現重複利用。類似生活中的公共交 通工具。

好處: 1. 提高響應速度(减少了創建新線程的時間)

2.降低資源消耗(重複利用線程池中線程,不需要每次都創建)

3.便於線程管理?corePoolSize:核心池的大小 ,/maximumPoolSize:最大線程數,keepAliveTime:線程沒有任務時最多保持多長時間後會終止 線程池:提供了一個線程隊列,隊列中保存著所有等待狀態的線程,避免了創建於銷毀的額外開銷,提高了響應的速度

java.util.concurrent.Executor :負責線程的使用與調度的根接口 –ExecutorService 子接口:線程池的主要接口,繼承Executor –ThreadPoolExecutor 線程池的實現類 –ScheduledExecutorService 子接口:負責線程的調度,繼承ExecutorService –ScheduledThreadPoolExecutor 繼承ThreadPoolExecutor 實現ScheduledExecutorService

public class ThreadPoolTest {
public static void main(String[] args) {
// 1.創建線程池 5個線程
ExecutorService pool = Executors.newFixedThreadPool(5);
ThreadPoolDemo tpd = new ThreadPoolDemo();
/*// 2.為線程池中的線程分配任務
for (int i = 0; i < 5; i++) {
pool.submit(tpd);
}
// 3.關閉線程池,保證所有線程的任務完成才會關閉
// shutdownNow() 立即關閉,不管任務做完沒有
pool.shutdown();*/
List<Future<Integer>> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
// Future得到Callable的返回值
Future<Integer> future = pool.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int j = 0; j <= 100; j++) {
sum += j;
}
return sum;
}
});
list.add(future);
}
pool.shutdown();
for(Future<Integer> future : list) {
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
class ThreadPoolDemo implements Runnable{
private int i = 0;
@Override
public void run() {
while(i <= 100){
System.out.println(Thread.currentThread().getName() + " : " + i++);
}
}
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.

線程調度

ScheduledExecutorService newScheduledThreadPool() 創建固定大小的線程,可以延遲或定時的執行任務

public class ScheduledThreadPoolTest {
public static void main(String[] args) {
ScheduledExecutorService pool = Executors.newScheduledThreadPool(5);
for (int i = 0; i < 5; i++) {
Future<Integer> result = pool.schedule(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int num = new Random().nextInt(100);
System.out.println(Thread.currentThread().getName() + ":" + num);
return num;
}
}, 3, TimeUnit.SECONDS);// 延遲3s執行
try {
System.out.println(result.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
pool.shutdown();
}
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.

TimeUnit的用法

ForkJoinPool 分支/合並框架 工作竊取

Fork/Join 框架:就是在必要的情况下,將一個大任務,進行拆分(fork)成 若幹個小任務(拆到不可再拆時),再將一個個的小任務運算的結果進 行 join 匯總

采用 “工作竊取”模式(work-stealing): 當執行新的任務時它可以將其拆分分成更小的任務執行,並將小任務加 到線程隊列中,然後再從一個隨機線程的隊列中偷一個並把它放在自己的隊 列中

相對於一般的線程池實現,fork/join框架的優勢體現在對其中包含的任務 的處理方式上.在一般的線程池中,如果一個線程正在執行的任務由於某些 原因無法繼續運行,那麼該線程會處於等待狀態。而在fork/join框架實現中, 如果某個子問題由於等待另外一個子問題的完成而無法繼續運行。那麼處理 該子問題的線程會主動尋找其他尚未運行的子問題來執行.這種方式减少了 線程的等待時間,提高了性能

Stream API 可以聲明性地通過 parallel() 與 sequential() 在並行流與順序流之間進行切換

public class ForkJoinPoolTest {
public static void main(String[] args) {
Instant start = Instant.now();
ForkJoinPool pool = new ForkJoinPool();
// RecursiveTask<V> extends ForkJoinTask<V>
ForkJoinTask<Long> task = new ForkJoinTest(0L, 50000000000L);
Long sum = pool.invoke(task);
System.out.println(sum);
Instant end = Instant.now();
System.out.println(Duration.between(start, end).toMillis());
}
@Test
public void test2() { // 18256
Instant start = Instant.now();
long sum = 0;
for (long i = 0; i <= 50000000000L; i++) {
sum += i;
}
Instant end = Instant.now();
System.out.println(Duration.between(start, end).toMillis());
}
@Test
public void test3() { // 14444
// 對ForkJoin的改進
Instant start = Instant.now();
// rangeClosed 生成連續的數
long sum1 = LongStream.rangeClosed(0, 50000000000L)
.parallel()
.reduce(0, Long::sum); // 第二個參數 是函數式接口LongBinaryOperator
# 最後
各比特讀者,由於本篇幅度過長,為了避免影響閱讀體驗,下面我就大概概括了整理了
**[CodeChina開源項目:【一線大廠Java面試題解析+核心總結學習筆記+最新講解視頻】](https://ali1024.coding.net/public/P7/Java/git)**
![來吧,展示,從零開始學Java編程_Java](https://s6.51cto.com/images/20210918/1631914625891867.jpg)
![來吧,展示,從零開始學Java編程_後端_02](https://s9.51cto.com/images/20210918/1631914625834063.jpg)
![來吧,展示,從零開始學Java編程_Java_03](https://s5.51cto.com/images/20210918/1631914626183826.jpg)
![來吧,展示,從零開始學Java編程_Java_04](https://s7.51cto.com/images/20210918/1631914626366400.jpg)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
版权声明:本文为[程序員小秘境]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/09/20210918054445741w.html