簡單的線程池,體現線程的複用
不使用Executors.newFixedThreadPool(int)、Executors.newSingleThreadExecutor()、Executors.newCachedThreadPool(),而是通過ThreadPoolExecutor的7個參數的構造函數來創建線程池。不使用的原因寫在:https://www.cnblogs.com/xdcat/p/12981188.html。
1 public static void selfThreadPool() { 2 Runtime.getRuntime().availableProcessors(); 3 ExecutorService threadPool = new ThreadPoolExecutor( 4 2,//corePoolSize 5 5,//maximumPoolSize 6 1L,//keepAliveTime 7 TimeUnit.SECONDS,new LinkedBlockingDeque<>(3), 8 Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy()); 9 try { 10 for (int i = 1; i <= 10; i++) { 11 final int tmp = i; 12 threadPool.execute(()->{ 13 System.out.println(Thread.currentThread().getName()+"線程"+",執行任務"+tmp); 14 }); 15 } 16 }catch (Exception e){ 17 e.printStackTrace(); 18 }finally { 19 threadPool.shutdown(); 20 } 21 }
輸出結果
pool-2-thread-1執行任務0 pool-2-thread-4執行任務3 pool-2-thread-1執行任務5 pool-2-thread-2執行任務1 pool-2-thread-3執行任務2 pool-2-thread-2執行任務8 pool-2-thread-1執行任務7 pool-2-thread-4執行任務6 pool-2-thread-5執行任務4 pool-2-thread-3執行任務9
消費者和生產者模式
使用傳統的鎖來實現,還可以通過阻塞隊列實現,阻塞隊列的實現見https://www.cnblogs.com/xdcat/p/12958057.html
1 /** 2 * 一個初始值爲零的變量,兩個線程對其交替操作,一個加1一個減1, 3 */ 4 class Cakes { 5 private int cakeNumber = 0; 6 private Lock lock = new ReentrantLock(); 7 private Condition condition = lock.newCondition(); 8 public void increment() throws InterruptedException { 9 lock.lock(); 10 try{ 11 //判斷 (多線程判斷用while) 12 while(cakeNumber != 0){ 13 //等待 不能生產 14 condition.await(); 15 } 16 //進行操作(生產蛋糕) 17 cakeNumber++; 18 System.out.println(Thread.currentThread().getName()+"烹飪" + cakeNumber+"個蛋糕"); 19 //通知喚醒 20 condition.signalAll(); 21 }catch(Exception e){ 22 e.printStackTrace(); 23 }finally{ 24 lock.unlock(); 25 } 26 } 27 28 public void decrement() throws InterruptedException { 29 lock.lock(); 30 try{ 31 //判斷 (多線程判斷用while) 32 while(cakeNumber ==0){ 33 //等待 不能消費 34 condition.await(); 35 } 36 //進行操作 37 cakeNumber--; 38 System.out.println(Thread.currentThread().getName()+"吃完蛋糕,還剩" + cakeNumber+"個蛋糕"); 39 //通知喚醒 40 condition.signal(); 41 }catch(Exception e){ 42 e.printStackTrace(); 43 }finally{ 44 lock.unlock(); 45 } 46 } 47 } 48 public class ProdConsumerTraditionDemo { 49 public static void main(String[] args) { 50 Cakes cake = new Cakes(); 51 new Thread(()->{ 52 for (int i = 0; i < 5; i++) { 53 try { 54 cake.increment(); 55 } catch (InterruptedException e) { 56 e.printStackTrace(); 57 } 58 } 59 },"廚師").start(); 60 new Thread(()->{ 61 for (int i = 0; i < 5; i++) { 62 try { 63 cake.decrement(); 64 } catch (InterruptedException e) { 65 e.printStackTrace(); 66 } 67 } 68 },"顧客").start(); 69 } 70 }
實現自旋鎖
嘗試獲取鎖的線程不會阻塞,而是採用循環的方式去獲取鎖,好處是減少了線程上下文切換的消耗,缺點是循環會消耗CPU。
1 public class SpinLockDemo { 2 //原子引用線程 3 AtomicReference<Thread> atomicReference = new AtomicReference<>(); 4 5 public void myLock(){ 6 Thread thread = Thread.currentThread();
8 while(!atomicReference.compareAndSet(null,thread)){ 9 //匹配則不進入循環 獲取鎖後!=null進入循環 釋放鎖後被set爲null退出循環
16 }
18 } 19 20 public void myUnlock(){ 21 Thread thread = Thread.currentThread(); 22 atomicReference.compareAndSet(thread,null);
24 } 25 public static void main(String[] args) { 26 SpinLockDemo spinLockDemo = new SpinLockDemo(); 27 new Thread(()->{ 28 spinLockDemo.myLock();
35 spinLockDemo.myUnlock(); 36 },"A").start();
42 new Thread(()->{ 43 spinLockDemo.myLock();
50 spinLockDemo.myUnlock(); 51 },"B").start(); 52 } 53 }
實現阻塞隊列
1 public class MyBlockQueue { 2 private List<Integer> queue = new ArrayList<>();//用數組實現的話定義索引變量就可以 3 private volatile int curSize; 4 private volatile int capacity; 5 private Lock lock = new ReentrantLock(); 6 private final Condition notFull = lock.newCondition();//不滿 7 private final Condition notNull = lock.newCondition();//不空 8 9 public MyBlockQueue(int capacity) { 10 this.capacity = capacity; 11 } 12 13 public void add(int value){ 14 lock.lock(); 15 try{ 16 while(curSize == capacity){ 17 //等待隊列不滿 18 notFull.await(); 19 } 20 queue.add(value); 21 ++curSize; 22 // System.out.println("入隊成功"); 23 notNull.signal();//通知隊列不爲空 24 }catch(Exception e){ 25 e.printStackTrace(); 26 }finally{ 27 lock.unlock(); 28 } 29 } 30 31 public Integer take(){ 32 lock.lock(); 33 Integer x = null; 34 try{ 35 while(curSize == 0){ 36 //等待隊列不爲空 37 notNull.await(); 38 } 39 x = queue.remove(0); 40 curSize--; 41 notFull.signal(); 42 }catch(Exception e){ 43 e.printStackTrace(); 44 }finally{ 45 lock.unlock(); 46 } 47 return x; 48 } 49 50 public static void main(String[] args) { 51 MyBlockQueue queue = new MyBlockQueue(5); 52 new Thread(()->{ 53 for (int i = 0; i < 10; i++) { 54 System.out.println(Thread.currentThread().getName()+"消費"+queue.take()); 55 } 56 }).start(); 57 new Thread(()->{ 58 for (int i = 0; i < 10; i++) { 59 queue.add(i); 60 System.out.println(Thread.currentThread().getName()+"生產"+i); 61 } 62 63 }).start(); 64 } 65 }
多線程交替打印ABC
1 import java.util.concurrent.locks.Condition; 2 import java.util.concurrent.locks.Lock; 3 import java.util.concurrent.locks.ReentrantLock; 4 10 class Plat{ 11 private int id = 1; // 編號 12 private Lock lock = new ReentrantLock(); 13 private Condition a = lock.newCondition(); 14 private Condition b = lock.newCondition(); 15 private Condition c = lock.newCondition(); 16 public void printA(){ 17 lock.lock(); 18 try{ 19 while (id != 1){ 20 a.await(); 21 } 22 System.out.println("A"); 23 id = 2; 24 b.signal(); 25 }catch(Exception e){ 26 e.printStackTrace(); 27 }finally{ 28 lock.unlock(); 29 } 30 } 31 public void printB(){ 32 lock.lock(); 33 try{ 34 while (id != 2){ 35 b.await(); 36 } 37 System.out.println("B"); 38 id = 3; 39 c.signal(); 40 }catch(Exception e){ 41 e.printStackTrace(); 42 }finally{ 43 lock.unlock(); 44 } 45 } 46 public void printC(){ 47 lock.lock(); 48 try{ 49 while (id != 3){ 50 c.await(); 51 } 52 System.out.println("C"); 53 id = 1; 54 a.signal(); 55 }catch(Exception e){ 56 e.printStackTrace(); 57 }finally{ 58 lock.unlock(); 59 } 60 } 61 62 } 63 public class PrintAbc { 64 public static void main(String[] args) throws InterruptedException { 65 Plat plat = new Plat(); 66 for (int i = 0; i < 3; i++) { 67 new Thread(()->{ 68 plat.printA(); 69 }).start(); 70 new Thread(()->{ 71 plat.printB(); 72 }).start(); 73 new Thread(()->{ 74 plat.printC(); 75 }).start(); 76 } 77 } 78 }
兩個線程實現交叉打印1-10000
同步代碼塊實現
1 public class PrintOneThousand { 2 private static volatile Integer counter = 0; 3 private static Object monitor = new Object(); 4 5 public static void main(String[] args) { 6 new Thread(()->{ 7 while (true){ 8 synchronized (monitor){ 9 if (counter % 2 != 0){ 10 continue; 11 } 12 int i = ++counter; 13 if (i > 1000){ 14 return; 15 } 16 System.out.println("奇數線程:" + i); 17 try { 18 monitor.notify(); 19 monitor.wait(); 20 } catch (InterruptedException e) { 21 e.printStackTrace(); 22 } 23 } 24 } 25 }).start(); 26 27 new Thread(()->{ 28 while (true){ 29 synchronized (monitor){ 30 if (counter % 2 == 0){ 31 continue; 32 } 33 int i = ++counter; 34 if (i > 1000){ 35 return; 36 } 37 System.out.println("偶數線程:" + i); 38 try { 39 monitor.notify(); 40 monitor.wait(); 41 } catch (InterruptedException e) { 42 e.printStackTrace(); 43 } 44 } 45 } 46 }).start(); 47 } 48 }
volatitle實現
public class PrintOneThousand{ private static volatile boolean loopForOdd = true; private static volatile boolean loopForEven = true; private static volatile int counter = 1; private static boolean flag = true; public static void main(String[] args) throws InterruptedException { // 先啓動奇數線程 loopForOdd = false; new Thread(()->{ while (flag) { while (loopForOdd) { } int counter = PrintOneThousand.counter; if (counter > 100) { flag=false; break; } System.out.println("奇數線程:" + counter); PrintOneThousand.counter++; // 修改volatile,通知偶數線程停止循環,同時,準備讓自己陷入循環 loopForEven = false; loopForOdd = true; } }).start(); new Thread(()->{ while (flag) { while (loopForEven) { } int counter = PrintOneThousand.counter; if (counter > 100) { flag=false; break; } System.out.println("偶數線程:" + counter); PrintOneThousand.counter++; // 修改volatile,通知奇數線程停止循環,同時,準備讓自己陷入循環 loopForOdd = false; loopForEven = true; } }).start(); } }