自學了一段時間的多線程知識,嘗試了做了幾個編程題,發現想象中很簡單的功能,自己真寫起來要花費遠超自己想象的功夫,知識點易學,不易用啊.
面試題1:編寫程序實現,子線程循環10次,接着主線程循環20次,接着再子線程循環10次,主線程循環20次,如此反復,循環50次.
package com.wang.reflect; //編寫功能類,實現子線程和主線程的功能
class Function{ private boolean flag=false; //子線程要實現的功能
public synchronized void sub(){ while(flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } for(int i=0;i<10;i++){ //for循環內定義子線程的功能,這里簡單的假設為打印一句話,主線程同理
System.out.println("sub"+i); } flag=true; this.notify(); } //主線程要實現的功能
public synchronized void main(){ while(!flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } for(int i=0;i<20;i++){ System.out.println("main"+i); } flag=false; this.notify(); } } public class Demo01 { public static void main(String[] args) { final Function f=new Function(); new Thread( new Runnable(){ @Override public void run() { for(int i=0;i<50;i++){ f.sub(); } } } ).start(); for(int i=0;i<50;i++){ f.main(); } } }
JDK1.5以后,出現了Lock和condition,Lock類似於synchronized功能,用來進行線程同步,Condition功能類似於Object類中的wait和notify方法,用於線程間的通信.上面的代碼可以用Lock和Condition來改進,如下:
package com.wang.reflect; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; //編寫功能類,實現子線程和主線程的功能 class Function{ private boolean flag=false; Lock lock=new ReentrantLock(); Condition con=lock.newCondition(); //子線程要實現的功能 public void sub(){ lock.lock(); try { while(flag){ try { con.await(); } catch (InterruptedException e) { e.printStackTrace(); } } for(int i=0;i<10;i++){ //for循環內定義子線程的功能,這里簡單的假設為打印一句話,主線程同理 System.out.println("sub"+i); } flag=true; con.signal(); } finally{ lock.unlock(); } } //主線程要實現的功能 public synchronized void main(){ lock.lock(); try { while (!flag) { try { con.await(); } catch (InterruptedException e) { e.printStackTrace(); } } for (int i = 0; i < 20; i++) { System.out.println("main" + i); } flag = false; con.signal(); } finally{ lock.unlock(); } } } public class Demo01 { public static void main(String[] args) { final Function f=new Function(); new Thread( new Runnable(){ @Override public void run() { for(int i=0;i<50;i++){ f.sub(); } } } ).start(); for(int i=0;i<50;i++){ f.main(); } } }
面試題2:設計四個線程,其中兩個線程每次對變量i加1,另外兩個線程每次對i減1.
package com.wang.reflect; /** * 設計四個線程,其中兩個線程每次對變量i加1,另外兩個線程每次對i減1. * @author Administrator * */
public class Demo02 { private int i=0; public static void main(String[] args) { Demo02 demo=new Demo02(); Add add = demo.new Add(); Sub sub = demo.new Sub(); for(int i=1;i<=2;i++){ new Thread(add,"線程"+i).start(); new Thread(sub,"線程"+i).start(); } } //定義一個內部類Add,實現功能每次對i加一
class Add implements Runnable{ @Override public void run() { for(int i=0;i<10;i++){ addOne(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } //定義一個內部類Sub,實現功能每次對i減1
class Sub implements Runnable{ @Override public void run() { for(int i=0;i<10;i++){ subOne(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } public synchronized void addOne() { i++; System.out.println(Thread.currentThread().getName()+"加一的值為:"+i); } public synchronized void subOne(){ i--; System.out.println(Thread.currentThread().getName()+"減一的值為:"+i); } }
面試題3:自己編寫代碼,實現生產者-消費者模型功能.內容自由發揮,只需要表達思想.
代碼中,自定義一個學生類,有name和age屬性,屬於共享對象,生產者負責為studnet對象賦值,消費者負責打印出student對象的name和age的值,當生產者賦值完以后通知消費者來打印,消費者打印完以后,通知生產者重新設置.
package com.wang.reflect; //學生實體類作為共享資源
class Student { private String name;// 姓名
private int age;// 年齡
boolean flag;// 標記變量,判斷當前學生對象是否已創建賦值好 //生產者的功能 ,為studnet對象賦值
public synchronized void set(String name, int age) { if (this.flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.name = name; this.age = age; this.flag = true; this.notify(); } //消費者的功能,打印sutdent對象的內容
public synchronized void get() { if (!this.flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(name + ":::" + age); this.flag = false; this.notify(); } } // 模擬生產者線程類
class SetStudent implements Runnable { // 共享資源s
private Student s; private int x = 0; public SetStudent(Student s) { this.s = s; } @Override public void run() { while (true) { if (x % 2 == 0) { s.set("郭靖", 27); } else { s.set("黃蓉", 18); } x++; } } } // 模擬消費者線程類
class GetStudent implements Runnable { // 共享資源s
private Student s; public GetStudent(Student s) { this.s = s; } @Override public void run() { while (true) { s.get(); } } } // 測試類
public class Demo03{ public static void main(String[] args) { Student s = new Student(); SetStudent ss = new SetStudent(s); GetStudent gs = new GetStudent(s); Thread t1 = new Thread(ss, "生產者"); Thread t2 = new Thread(gs, "消費者"); t1.start(); t2.start(); } }
面試題4: 現有的程序代碼模擬產生了16個日志對象,並且需要運行16秒才能打印完這些日志,請在程序中增加4個線程去調用parseLog()方法來分頭打印這16個日志對象,程序只需要運行4秒即可打印完這些日志對象。
原始代碼如下:
public class Test { public static void main(String[] args){ System.out.println("begin:"+(System.currentTimeMillis()/1000)); /*模擬處理16行日志,下面的代碼產生了16個日志對象,當前代碼需要運行16秒才能打印完這些日志。 修改程序代碼,開四個線程讓這16個對象在4秒鍾打完。 */ for(int i=0;i<16;i++){ //這行代碼不能改動 final String log = ""+(i+1);//這行代碼不能改動 { Test.parseLog(log); } } } //parseLog方法內部的代碼不能改動 public static void parseLog(String log){ System.out.println(log+":"+(System.currentTimeMillis()/1000)); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }
改寫代碼如下:
package com.wang.reflect; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; public class Demo03 { public static void main(String[] args){ //定義一個線程共享的隊列容器,可以使得數據由隊列的一端輸入,從另外一端輸出 final BlockingQueue<String> queue=new ArrayBlockingQueue<String>(16); for(int i=0;i<4;i++){ new Thread(new Runnable(){ @Override public void run() { while(true){ try { parseLog(queue.take()); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } System.out.println("begin:"+(System.currentTimeMillis()/1000)); /*模擬處理16行日志,下面的代碼產生了16個日志對象,當前代碼需要運行16秒才能打印完這些日志。 修改程序代碼,開四個線程讓這16個對象在4秒鍾打完。 */ for(int i=0;i<16;i++){ //這行代碼不能改動 final String log = ""+(i+1);//這行代碼不能改動 { try { queue.put(log); } catch (InterruptedException e) { e.printStackTrace(); } } } } //parseLog方法內部的代碼不能改動 public static void parseLog(String log){ System.out.println(log+":"+(System.currentTimeMillis()/1000)); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }