java--線程--習題集錦

來源:互聯網
上載者:User

標籤:oat   hand   let   匿名類   case   current   unlock   mys   tst   

匿名類的一個好處是可以很方便的訪問外部的局部變數。
前提是外部的局部變數需要被聲明為final。(JDK7以後就不需要了)

======================

同步方法1:普通式

同步方法2:在對象方法裡 寫關鍵字,用this

同步方法3:在方法前,加上修飾符synchronized,效果等同方法2

==================

題目1--同步尋找檔案內容

把 練習-尋找檔案內容 改為多線程尋找檔案內容
原練習的思路是遍曆所有檔案,當遍曆到檔案是 .java的時候,尋找這個檔案的內容,尋找完畢之後,再遍曆下一個檔案

現在通過多線程調整這個思路:
遍曆所有檔案,當遍曆到檔案是.java的時候,建立一個線程去尋找這個檔案的內容,不必等待這個線程結束,繼續遍曆下一個檔案

package zsc.czy.zhonghe;import java.io.File;import java.io.FileReader;public class findContent {    public static void main(String[] args) {        File f = new File("d:/test");                search(f, "Hello");    }    public static void search(File f, String search) {        System.out.println(f); //d:\find.txt        System.out.println(f.getAbsolutePath());//      System.out.println(f.getName());//find.txt        if (f.isFile()) {            if (f.getName().toLowerCase().endsWith(".java")) {                new Thread(new Runnable() {                                        @Override                    public void run() {                        String fileContent = readFileConent(f);                        if (fileContent.contains(search)) {                            System.out.printf("找到子目標字串%s,在檔案:%s%n", search, f);                        }                    }                }).start();                            }        }        if(f.isDirectory()){            File[] fs = f.listFiles();            for(File file :fs){                search(file,search);            }        }    }    private static String readFileConent(File f) {        try (FileReader fr = new FileReader(f);) {            char[] c = new char[(int) f.length()];            fr.read(c);            String s = new String(c);            return s;        } catch (Exception e) {            return null;        }    }}
題目2--英雄充能

英雄有可以放一個技能叫做: 波動拳-a du gen。
每隔一秒鐘,可以發一次,但是只能連續發3次。

發完3次之後,需要充能5秒鐘,充滿,再繼續發。

package zsc.czy.thread;public class Hero {    String name;    int hp;    int damage;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getHp() {        return hp;    }    public void setHp(int hp) {        this.hp = hp;    }    public int getDamage() {        return damage;    }    public void setDamage(int damage) {        this.damage = damage;    }    public boolean isDead() {        return 0 >= hp ? true : false;    }    public void attackHero(Hero h) {        try {            // 為了表示攻擊需要時間,每次攻擊暫停1000毫秒            Thread.sleep(1000);        } catch (Exception e) {            e.printStackTrace();        }        h.hp -= damage;        System.out.format("%s 正在攻擊 %s,%s的血編程了 %.0f%n", name, h.name, h.name,                h.hp);        if (h.isDead()) {            System.out.println(h.name + "死了");        }    }    int totalTime = 3;    public void adugen() {        while (true) {            for (int i = 0; i < totalTime; i++) {                System.out.printf("波動拳第%d發%n", i + 1);                try {                    Thread.sleep(1000);                } catch (Exception e) {                    // TODO: handle exception                }            }            System.out.println("開始為時5秒的充能");            try {                Thread.sleep(5000);            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }    public static void main(String[] args) {        Hero h = new Hero();        h.name = "紅仔";        h.adugen();    }}
題目3--破解密碼
  1. 產生一個長度是3的隨機字串,把這個字串作為當做密碼

  2. 建立一個破解線程,使用窮舉法,匹配這個密碼

  3. 建立一個日誌線程,列印都用過哪些字串去匹配,這個日誌線程設計為守護線程

提示: 破解線程把窮舉法產生的可能密碼放在一個容器中,日誌線程不斷的從這個容器中拿出可能密碼,並列印出來。 如果發現容器是空的,就休息1秒,如果發現不是空的,就不停的取出,並列印。

==============================

HashMap不嚴格 可以存放 null --不是安全執行緒的類
Hashtable嚴格

ArrayList是非安全執行緒的
Vector是安全執行緒的類

====================

題目4-安全執行緒的MyStack

藉助把非安全執行緒的集合轉換為安全執行緒,用另一個方式完成 練習-安全執行緒的MyStack

題目5--死結

3個同步對象a, b, c
3個線程 t1,t2,t3

故意設計情境,使這3個線程彼此死結

//我這樣設計是不成功的package zsc.czy.thread;public class SiSuo {    public static void main(String[] args) {        final Hero ahri = new Hero();        ahri.name = "九尾妖狐";        final Hero annie = new Hero();        annie.name = "安妮";        final Hero leqing = new Hero();        annie.name = "李青";        Thread t1 = new Thread() {            public void run() {                // 佔有九尾妖狐                synchronized (ahri) {                    System.out.println("t1 已佔有九尾妖狐");                    try {                        // 停頓1000毫秒,另一個線程有足夠的時間佔有安妮                        Thread.sleep(1000);                    } catch (InterruptedException e) {                        // TODO Auto-generated catch block                        e.printStackTrace();                    }                    System.out.println("t1 試圖佔有安妮");                    System.out.println("t1 等待中 。。。。");                    synchronized (annie) {                        System.out.println("do something");                    }                }            }        };        t1.start();        Thread t2 = new Thread() {            public void run() {                // 佔有安妮                synchronized (annie) {                    System.out.println("t2 已佔有安妮");                    try {                        // 停頓1000秒,另一個線程有足夠的時間佔有暫用九尾妖狐                        Thread.sleep(1000);                    } catch (InterruptedException e) {                        // TODO Auto-generated catch block                        e.printStackTrace();                    }                    System.out.println("t2 試圖佔有李青");                    System.out.println("t2 等待中 。。。。");                    synchronized (leqing) {                        System.out.println("do something");                    }                }            }        };        t2.start();                Thread t3 = new Thread(){            public void run() {                synchronized (leqing) {                    System.out.println("t3已佔有李青");                    try {                        Thread.sleep(1000);                    } catch (InterruptedException e) {                                                e.printStackTrace();                    }                    System.out.println("t3 試圖佔有九尾妖狐");                    System.out.println("t3 等待中 。。。。");                }                synchronized (ahri) {                    System.out.println("do something");                }                            };        };        t3.start();    }}
正確做法為:
package multiplethread; public class TestThread {           public static void main(String[] args) {        Object a = new Object();        Object b = new Object();        Object c = new Object();         Thread t1 =new Thread(){            public void run(){                synchronized (a) {                    try {                        Thread.sleep(1000);                    } catch (InterruptedException e) {                        // TODO Auto-generated catch block                        e.printStackTrace();                    }                    synchronized (b) {                        synchronized (c) {                                                     }                    }                }              }        };        Thread t2 =new Thread(){            public void run(){                synchronized (c) {                    try {                        Thread.sleep(1000);                    } catch (InterruptedException e) {                        // TODO Auto-generated catch block                        e.printStackTrace();                    }                    synchronized (a) {                        synchronized (b) {                                                     }                    }                }              }        };        Thread t3 =new Thread(){            public void run(){                synchronized (b) {                    try {                        Thread.sleep(1000);                    } catch (InterruptedException e) {                        // TODO Auto-generated catch block                        e.printStackTrace();                    }                    synchronized (c) {                        synchronized (a) {                                                     }                    }                }              }        };         t1.start();        t2.start();        t3.start();           }         }

================

使用wait和notify進行線程互動

this.wait()表示 讓佔有this的線程等待,並臨時釋放佔有
this.notify() 表示通知那些等待在this的線程,可以蘇醒過來了。

public synchronized void recover() {        hp = hp + 1;         System.out.printf("%s 回血1點,增加血後,%s的血量是%.0f%n", name, name, hp);        // 通知那些等待在this對象上的線程,可以醒過來了,如第20行,等待著的減血線程,蘇醒過來        this.notify();    }    // 掉血  同步方式和上面效果一樣 這個方式    public void hurt() {        synchronized (this) {            if (hp == 1) {                // 讓佔有this的減血線程,暫時釋放對this的佔有,並等待                try {                    this.wait();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            hp = hp - 1;            System.out.printf("%s 減血1點,減少血後,%s的血量是%.0f%n", name, name, hp);        }    }

別忘了Thread 父類也是Object

題目--線程互動

假設加血線程運行得更加頻繁,英雄的最大血量是1000

設計加血線程和減血線程的互動,讓回血回滿之後,加血線程等待,直到有減血線程減血

    // 回血    public synchronized void recover() {                if(hp>=1000){            try {                this.wait(); //後加的            } catch (InterruptedException e) {                                e.printStackTrace();            }        }                hp = hp + 1;        System.out.printf("%s 回血1點,增加血後,%s的血量是%.0f%n", name, name, hp);        // 通知那些等待在this對象上的線程,可以醒過來了,如第73行,等待著的減血線程,蘇醒過來        this.notify();     }    // 掉血  同步方式和上面效果一樣 這個方式    public void hurt() {        synchronized (this) {            if (hp == 1) {                // 讓佔有this的減血線程,暫時釋放對this的佔有,並等待                try {                    this.wait();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            hp = hp - 1;            System.out.printf("%s 減血1點,減少血後,%s的血量是%.0f%n", name, name, hp);                        //notify() 的意思是,通知一個等待在這個同步對象上的線程,你可以蘇醒過來了,有機會重新佔用當前對象了。            //掉血之後,喚醒等待的線程            this.notify();//後加的        }    }
題目--多線程互動

在上面的練習的基礎上,增加回血線程到2條,減血線程到5條,同時運行。

運行一段時間,觀察會發生的錯誤,分析錯誤原因,並考慮解決辦法

題目--生產者消費者問題

生產者消費者問題是一個非常典型性的線程互動的問題。

  1. 使用棧來存放資料
    1.1 把棧改造為支援安全執行緒
    1.2 把棧的邊界操作進行處理,當棧裡的資料是0的時候,訪問pull的線程就會等待。 當棧裡的資料時200的時候,訪問push的線程就會等待
  2. 提供一個生產者(Producer)線程類,生產隨機大寫字元壓入到堆棧
  3. 提供一個消費者(Consumer)線程類,從堆棧中彈出字元並列印到控制台
  4. 提供一個測試類別,使兩個生產者和三個消費者線程同時運行,結果類似如下 :

==================

Lock

題目

在練習-安全執行緒的MyStack 練習中,使用synchronized把MyStack修改為了安全執行緒的類。

接下來,藉助Lock把MyStack修改為安全執行緒的類

把synchronized去掉
使用lock佔用鎖
使用unlock釋放鎖
必須放在finally執行,萬一heros.addLast拋出異常也會執行

package multiplethread;    import java.util.LinkedList;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock; import charactor.Hero;    public class MyStack {        LinkedList<Hero> heros = new LinkedList<Hero>();     Lock lock = new ReentrantLock();         //把synchronized去掉    public  void push(Hero h) {        try{            //使用lock佔用鎖            lock.lock();            heros.addLast(h);                  }        finally{            //使用unlock釋放鎖            //必須放在finally執行,萬一heros.addLast拋出異常也會執行            lock.unlock();        }         }        //把synchronized去掉    public  Hero pull() {        try{            //使用lock佔用鎖            lock.lock();            return heros.removeLast();                 }        finally{            //使用unlock釋放鎖            //必須放在finally執行,萬一heros.removeLast();拋出異常也會執行                      lock.unlock();        }    }        public Hero peek() {        return heros.getLast();    }            public static void main(String[] args) {     }    }
題目--藉助tryLock 解決死結問題

當多個線程按照不同順序佔用多個同步對象的時候,就有可能產生死結現象。

死結之所以會發生,就是因為synchronized 如果佔用不到同步對象,就會苦苦的一直等待下去,藉助tryLock的有限等待時間,解決死結問題

package multiplethread;  import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;  public class TestThread {      public static void main(String[] args) throws InterruptedException {        Lock lock_ahri = new ReentrantLock();        Lock lock_annie = new ReentrantLock();          Thread t1 = new Thread() {            public void run() {                // 佔有九尾妖狐                boolean ahriLocked = false;                boolean annieLocked = false;                                  try {                    ahriLocked = lock_ahri.tryLock(10, TimeUnit.SECONDS);                    if (ahriLocked) {                        System.out.println("t1 已佔有九尾妖狐");                        // 停頓1000秒,另一個線程有足夠的時間佔有安妮                        Thread.sleep(1000);                        System.out.println("t1 試圖在10秒內佔有安妮");                        try {                            annieLocked = lock_annie.tryLock(10, TimeUnit.SECONDS);                            if (annieLocked)                                System.out.println("t1 成功佔有安妮,開始啪啪啪");                            else{                                System.out.println("t1 老是佔用不了安妮,放棄");                            }                          } finally {                            if (annieLocked){                                System.out.println("t1 釋放安妮");                                lock_annie.unlock();                            }                        }                      }                } catch (InterruptedException e1) {                    // TODO Auto-generated catch block                    e1.printStackTrace();                } finally {                    if (ahriLocked){                        System.out.println("t1 釋放九尾狐");                        lock_ahri.unlock();                    }                }              }        };        t1.start();                  Thread.sleep(100);                  Thread t2 = new Thread() {            public void run() {                boolean annieLocked = false;                boolean ahriLocked = false;                                                  try {annieLocked = lock_annie.tryLock(10, TimeUnit.SECONDS);                                  if (annieLocked){                                              System.out.println("t2 已佔有安妮");                        // 停頓1000秒,另一個線程有足夠的時間佔有安妮                        Thread.sleep(1000);                        System.out.println("t2 試圖在10秒內佔有九尾妖狐");                        try {                            ahriLocked = lock_ahri.tryLock(10, TimeUnit.SECONDS);                            if (ahriLocked)                                System.out.println("t2 成功佔有九尾妖狐,開始啪啪啪");                            else{                                System.out.println("t2 老是佔用不了九尾妖狐,放棄");                            }                        }                        finally {                            if (ahriLocked){                                System.out.println("t2 釋放九尾狐");                                lock_ahri.unlock();                            }                                                          }                      }                } catch (InterruptedException e1) {                    // TODO Auto-generated catch block                    e1.printStackTrace();                } finally {                    if (annieLocked){                        System.out.println("t2 釋放安妮");                        lock_annie.unlock();                    }                                          }            }        };        t2.start();          }}
題目--生產者消費者問題

在練習-生產者消費者問題這個練習中,是用wait(), notify(), notifyAll實現了。

接下來使用Condition對象的:await, signal,signalAll 方法實現同樣的效果

package multiplethread; import java.util.LinkedList;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock; public class MyStack<T> {     LinkedList<T> values = new LinkedList<T>();     Lock lock = new ReentrantLock();    Condition condition = lock.newCondition();     public void push(T t) {        try {            lock.lock();            while (values.size() >= 200) {                try {                    condition.await();                } catch (InterruptedException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            }            condition.signalAll();            values.addLast(t);        } finally {            lock.unlock();        }     }     public T pull() {        T t=null;        try {            lock.lock();            while (values.isEmpty()) {                try {                    condition.await();                } catch (InterruptedException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            }            condition.signalAll();            t= values.removeLast();        } finally {            lock.unlock();        }        return t;    }     public T peek() {        return values.getLast();    }}
題目--使用AtomicInteger來替換Hero類中的synchronized

在給Hero的方法加上修飾符synchronized 這個知識點中,通過給hurt和 recover方法加上synchronized來達到安全執行緒的效果。

這一次換成使用AtomicInteger來解決這個問題

提示:int基本類型對應的是AtomicInteger,但是float基本類型沒有對應的AtomicFloat。 所以在這個練習中,把hp改為AtomicInteger即可。

java--線程--習題集錦

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.