JAVA笔记14__多线程共享数据(同步)/ 线程死锁 / 生产者与消费者应用案例 / 线程池...
生活随笔
收集整理的這篇文章主要介紹了
JAVA笔记14__多线程共享数据(同步)/ 线程死锁 / 生产者与消费者应用案例 / 线程池...
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
/*** 多線程共享數據* 線程同步:多個線程在同一個時間段只能有一個線程執行其指定代碼,其他線程要等待此線程完成之后才可以繼續執行。* 多線程共享數據的安全問題,使用同步解決。* 線程同步兩種方法:* 1.同步代碼塊* synchronized(要同步的對象){ 要同步的操作 }* 2.同步方法* public synchronized void method(){ 要同步的操作 }*/
public class Main {public static void main(String[] args) {MyThread s0 = new MyThread();Thread t1 = new Thread(s0,"one");Thread t2 = new Thread(s0,"two");t1.start();t2.start();}
}class MyThread implements Runnable{Object obj = new Object(); //同步的標記對象
@Overridepublic void run() {//同步代碼塊synchronized(obj){System.out.println(Thread.currentThread().getName()+" is doing...");try {Thread.sleep(1000);} catch (InterruptedException ex) {ex.printStackTrace();}System.out.println(Thread.currentThread().getName()+" finished.");}}
}
//Java語言的關鍵字,當它用來修飾一個方法或者一個代碼塊的時候,能夠保證在同一時刻最多只有一個線程執行該段代碼。
//1.當兩個并發線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內只能有一個線程得到執行。另一個線程必須等待當前線程執行完這個代碼塊以后才能執行該代碼塊。
//2.然而,當一個線程訪問object的一個synchronized(this)同步代碼塊時,另一個線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。
//3.尤其關鍵的是,當一個線程訪問object的一個synchronized(this)同步代碼塊時,其他線程對object中所有其它synchronized(this)同步代碼塊的訪問將被阻塞。
//4.第三個例子同樣適用其它同步代碼塊。也就是說,當一個線程訪問object的一個synchronized(this)同步代碼塊時,它就獲得了這個object的對象鎖。結果,其它線程對該object對象所有同步代碼部分的訪問都被暫時阻塞。
//5.以上規則對其它對象鎖同樣適用。
?
public class Main {public static void main(String[] args) {MyThread s0 = new MyThread();Thread t1 = new Thread(s0,"one");Thread t2 = new Thread(s0,"two");t1.start();t2.start();} }class MyThread implements Runnable{@Overridepublic void run() {doMethod();}/*** 同步方法,同步的是當前對象(this)*/public synchronized void doMethod(){System.out.println(Thread.currentThread().getName()+" is doing...");try {Thread.sleep(1000);} catch (InterruptedException ex) {ex.printStackTrace();}System.out.println(Thread.currentThread().getName()+" finished.");} }/*** 同步代碼會帶來性能降低的問題,擔高數據的安全性* 當編寫synchronized塊時,有幾個簡單準則可以遵循。* 1.使代碼塊保持簡短,把不隨線程變化的預處理和后處理移出synchronized塊。* 2.不要阻塞。如InputStream.read()。* 3.在持有鎖的時候,不要對其它對象調用方法。*/?
/*** 線程死鎖:同步過多,會造成死鎖*/ public class Main {public static void main(String[] args) {new MyThread();} }class MyThread implements Runnable{Customer c = new Customer();Waiter w = new Waiter();public MyThread(){new Thread(this).start();w.say(c);}@Overridepublic void run() {c.say(w);} }class Customer{ //顧客public synchronized void say(Waiter w){System.out.println("顧客說:先做再給錢!");w.doService();}public synchronized void doService(){System.out.println("顧客同意了,先給錢再做");} } class Waiter{ //服務員public synchronized void say(Customer c){System.out.println("服務員說:先給錢再做!");c.doService();}public synchronized void doService(){System.out.println("服務員同意了,先做再給錢");} }//Java語言的關鍵字,當它用來修飾一個方法或者一個代碼塊的時候,能夠保證在同一時刻最多只有一個線程執行該段代碼。
//1.當兩個并發線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內只能有一個線程得到執行。另一個線程必須等待當前線程執行完這個代碼塊以后才能執行該代碼塊。
//2.然而,當一個線程訪問object的一個synchronized(this)同步代碼塊時,另一個線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。
//3.尤其關鍵的是,當一個線程訪問object的一個synchronized(this)同步代碼塊時,其他線程對object中所有其它synchronized(this)同步代碼塊的訪問將被阻塞。
//4.第三個例子同樣適用其它同步代碼塊。也就是說,當一個線程訪問object的一個synchronized(this)同步代碼塊時,它就獲得了這個object的對象鎖。結果,其它線程對該object對象所有同步代碼部分的訪問都被暫時阻塞。
//5.以上規則對其它對象鎖同樣適用。
?
/*** 生產者與消費者應用案例:生產者不斷生產產呂,消費者不斷取走產品。* sleep與wait的區別:sleep不釋放對象鎖,wait釋放對象鎖。*/ public class Main {public static void main(String[] args) {Food f = new Food();Productor p = new Productor(f);Consumer c = new Consumer(f);new Thread(p).start();new Thread(c).start();} }class Productor implements Runnable{ //生產者:廚師 Food food;public Productor(Food f){this.food = f;}@Overridepublic void run() {for(int i=0;i<100;++i){if(i%2==0){food.set("西紅柿炒蛋"+i, "補充維生素C。"+i);}else{food.set("胡蘿卜炒肉"+i, "補充維生素A。"+i);}}} } class Consumer implements Runnable{ //消費者:服務員 Food food;Consumer(Food f){this.food = f;}@Overridepublic void run() {for(int i=0;i<100;++i){food.get();}} } class Food{String name;String content;boolean flag = true; //true可以生產,false可以拿走public synchronized void set(String name,String content){ //生產產品if(!flag){try {this.wait(); //讓當前線程進入等待池等待,沒有指定時間,需要其它線程喚醒//釋放對象鎖,讓出CPU} catch (InterruptedException ex) {ex.printStackTrace();}}this.name = name;try {Thread.sleep(300);} catch (InterruptedException ex) {ex.printStackTrace();}this.content = content;flag = false;this.notify(); //喚醒在該監視器上的一個線程 }public synchronized void get(){ //消費產品if(flag){try {this.wait(); //讓當前線程進入等待池等待,沒有指定時間,需要其它線程喚醒//釋放對象鎖,讓出CPU} catch (InterruptedException ex) {ex.printStackTrace();}}try {Thread.sleep(300);} catch (InterruptedException ex) {ex.printStackTrace();}System.out.println(this.name+":"+this.content);flag = true;this.notify(); //喚醒在該監視器上的一個線程 } }?
/*** 線程池是預先創建線程的一種技術。線程池在還沒有任務到來之前,創建一定數量的線程,放入空閑隊列中,* 然后對這些資源進行復用。減少頻繁的創建和銷毀對象。*/ public class Main {public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();//創建一個單線程的線程池ExecutorService es = Executors.newSingleThreadExecutor(); es.execute(t1);es.execute(t2);//創建一個固定大小的線程池ExecutorService es2 = Executors.newFixedThreadPool(2);es2.execute(t1);es2.execute(t2);es2.execute(t3);//創建一個可緩存的線程池ExecutorService es3 = Executors.newCachedThreadPool();es3.execute(t1);es3.execute(t2);//創建一個大小無限的線程池ExecutorService es4 = Executors.newScheduledThreadPool(2);es3.execute(t1);es3.execute(t2);} }class MyThread implements Runnable{@Overridepublic void run() {for(int i=0;i<10;++i){try {Thread.sleep(1000);} catch (InterruptedException ex) {ex.printStackTrace();}System.out.println("MyThread-"+i);}} }?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
轉載于:https://www.cnblogs.com/fish7/p/4174719.html
總結
以上是生活随笔為你收集整理的JAVA笔记14__多线程共享数据(同步)/ 线程死锁 / 生产者与消费者应用案例 / 线程池...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQL SERVER With语法[转]
- 下一篇: 重构改善既有代码的设计(笔记)