201871010123-呉リリ「オブジェクト指向プログラミング(Java)の」週17学習の概要
プロジェクト | コンテンツ |
この作品は、コースに属し | https://www.cnblogs.com/nwnu-daizh/ |
どこの仕事でこの要件 | https://www.cnblogs.com/nwnu-daizh/p/12073034.html |
ジョブの学習目標 | (1)プロパティと優先スケジューリング方法スレッドを理解し、マスター; (2)スレッド同期技術の概念と実装を把握します。 (3)Javaのスレッド包括的なプログラミング演習 |
パートI:スレッド同期テクノロジの概要
図1は、同時実行、マルチスレッド
複数のスレッド➢不明の実行の相対的順序を。
➢スレッドの実行順序の不確実性は、結果の不確実性を作成します。
➢マルチスレッドでは、多くの場合、共有データ操作のための不確実性を作成します。
2、スレッドの同期
a)は、マルチスレッドを同時に実行不確か溶液:スレッド同期機構の導入
b)はJavaのマルチスレッド同期方法の2があります。
ReentrantLockのを導入-java SE 5.0クラス
●ReentrantLockの()
構築物は、再入可能ロックのクリティカルセクションを保護するために使用することができます
●ReentrantLockの(ブールフェア)
公正な政策とロックの建設。フェアロック好み最長待機しているスレッド。しかし、この公正を確保するために、パフォーマンスが大幅に削減されます。だから、デフォルトでは、ロックが公正に強制されていません。
- 共有メモリのクラスメソッドの前に修飾同期プラス。
......
公共同期の静的な無効サブ(int型メートル)
......
(1)溶液A:ロックオブジェクトとターゲット条件
以下と保護ReentrantLockのコードブロックの基本構造:
myLock.lock(); 試す{ クリティカルセクション } 最後に { myLock.unlock()。 }
ロックオブジェクトおよび条件オブジェクトに関するキーポイント:
➢いつでも唯一のスレッドが保護でコードを実行していることを確実にするために、ロック・コード・セグメントを保護します。
➢ロック・マネージャは、スレッドは、保護されたコード・セグメントを入力しようとします。
➢ロックは、一つ以上の関連していてもよい条件オブジェクト。
➢各条件オブジェクトの管理者のスレッドが保護されたコード・セグメントに参入しているが、実行することはできません。
クリティカルエリア条件オブジェクトのawait()、信号()、 signalAll() スレッド間の相互作用を達成するための方法
●空のawait()
待機セットにスレッドの状態。
●空signalAll()
待機を解除するための条件は、すべてのスレッドをブロックし、濃縮しました。
●無効信号()
ランダム、ブロック解除のセットで待機状態からスレッドを選択します。
➢クリティカルセクション内のスレッドは、この問題について、あなたは一時的に待ってCPUを使用する権利を放棄するために、このスレッドを作るために、ロックオブジェクトのawait()メソッドを使用し、他のスレッドがこの同期方法を使用できるようにしなければならないことがあります。
スレッドがクリティカルセクションを終了した場合➢、アプリケーションがランダムにスレッドのブロック解除を選択葛。
スレッドがクリティカル領域、実行のnotifyAll()メソッドを通知を終了した場合➢すべての原因スレッドが待機の最後にこの重要な地域を待っています。
(2)対処方法2:synchronizedキーワード
synchronizedキーワードの役割:
➢同期方法は、方法を変更した後、クラスは、同期方式と呼ばれます。
➢限りスレッドが同期メソッドにアクセスしているように、他のスレッドは、スレッドがフロントからブロックされたスレッド同期メソッドの復帰をウェイクアップするまで、同期方法がブロックされますアクセスしたい、他の当事者は、スレッドの同期方法を入力することもできます。
スレッド間の相互作用の同期処理で実行される方法では3)(ウェイトを用いて、通知とのnotifyAll()
●空のnotifyAll()
これらの呼び出しオブジェクトのスレッドでwaitメソッドのブロックを解除。この方法は、シンクブロック又は内部同期方法で呼び出すことができます。現在のスレッドがオブジェクトのロックホルダではない場合、は、IllegalMonitorStateExceptionメソッドは例外をスローします。
●無効)(通知
ランダムにオブジェクトのスレッドのブロック解除のコール待ち方法を選択します。この方法では、唯一の同期方法やシンクブロックと呼ばれることができます。現在のスレッドがオブジェクトのロックホルダではない場合、は、IllegalMonitorStateExceptionメソッドは例外をスローします。
●空の待機は()
それが通知されるまで待機状態にスレッドの原因となります。このメソッドは同期メソッドを呼び出すことができます。現在のスレッドがオブジェクトのロックホルダではない場合、この方法は、11 llegalMonitorStateException例外がスローされます。(ミリ秒のロング)●待機を無効
●無効待ち時間(ミリ秒、int型またはnanosのロングが)
それは、通知、または指定した時間後に完了するまで待機状態にスレッドの原因となります。これらのメソッドは、唯一の同期方法呼び出すことができます。現在のスレッドがオブジェクトのロックを所有していない場合IlalMonitorStateExceptionメソッドは例外をスローします。
パラメータ:ミリ秒(ミリ秒)
またはnanosナノ秒、<1000000
➢スレッド同期方法は、それはあなたがこのスレッドが一時的に待ってCPUを使用する権利を放棄し、他のスレッドがこの同期方法を使用できるようにするために待機()メソッドを使用する必要があり、必要な問題である可能性があり、使用。
あなたがスレッドの同期方法を使い果たし、アプリケーション実行した場合➢通知()メソッドは、ランダムに起因する最後のを待っている待機中のスレッドで、この方法の使用に同期を選択します。
➢あなたが原因終了を待っている待機中のスレッドで、このメソッドを使用することにすべての同期スレッド同期方法の、アプリケーションの実行notifyAl()メソッドの通知を実行する場合。パートII:実験の部
実験17 スレッド同期制御
実験時間 201 。8 -12- 10
1 、実験目的と要件
(1)は、スレッド同期技術の概念と実装をつかみ、
(2)総合的なプログラミングの練習のスレッド
2 、実験及びステップ
実験 1:試験手順とコードのコメント。
試験手順 1:
リットル で Elipse デバッグ教育環境 651 ポケットベル 14-7 、プログラムのプログラムを理解を合わせた結果、
Lは、 オブジェクトの実現のための同期ロックオブジェクトと条件をマルチスレッドの使用を習得しました。
次のようにSynchBankTest.javaコードは次のとおりです。
同期パッケージ; / ** *このプログラムのショーどのように安全にマルチスレッドアクセスデータ構造 * @version 1.31 2015年6月21日 * @authorケイHorstmann * / publicクラスSynchBankTest { のpublic static int型NACCOUNTS決勝= 100; のpublic static final二重INITIAL_BALANCE = 1000; のpublic static final二重MAX_AMOUNT = 1000; のpublic static final int型DELAY = 10; 公共の静的無効メイン(文字列[] args) { 銀行銀行=新しい新しい銀行(NACCOUNTS、INITIAL_BALANCE); のため(INT I = 0。 I <NACCOUNTS; I ++) { int型fromAccount = I; //は、ラムダ式を使用して、Runnableインタフェースの関数で RunnableをR&LT =() - > { トライ { 一方、(TRUE) { int型toAccount =(INT)(bank.size()* Math.random())。 重量= MAX_AMOUNT * Math.random(); bank.transfer(fromAccount、toAccount、量)。 Thread.sleep((int型)(DELAY * Math.random())); //线程的休眠状态 } } キャッチ(InterruptedExceptionある電子) { } }。 スレッドt =新しいスレッド(R) t.start(); } } }
次のようにBank.javaコードは次のとおりです。
同期パッケージ変更のため、 * ;. java.utilのインポートクラス のインポートjava.util.concurrent.locks * ;. / ** *多くの銀行は、銀行口座を持っている、それはシリアル化するためにロックを使用してアクセス * @version 1.30 2004-08-01 *ケイHorstmann @author * / publicクラス銀行 { 民間最終ダブル[]アカウント、 プライベートロックbankLock; //オブジェクトをロックし 、民間条件sufficientFundsを; //条件オブジェクト / ** *構文銀行が 口座の* @param数 * @param各初期口座残高 * / パブリック・バンク(N-INT、ダブルinitialBalance)は { [N-】ダブル新しい新しい=アカウント; Arrays.fill(アカウント、initialBalance); ReentrantLockのbankLockの新しい新=(); sufficientFunds bankLock.newCondition =(); } / ** *お金つのアカウントから別の アカウントから転送* @param * @paramに入金 * @param転送量 * / 公共空転送(int型から、 intに、ダブル量)InterruptedExceptionあるスロー { //添加ロック; bankLock.lock() のtry { 一方(アカウント【から<AMOUNT) sufficientFunds.awaitを();のawait条件オブジェクトのメソッドへの//呼び出しは、ブロックされた状態になります System.out.print(にThread.currentThread());スレッドオブジェクトの実行スレッドの//出力代表 アカウント[から] - = AMOUNT; System.out.printf( "%10.2f%DからDへ%"、AMOUNT、 )へ、から、 アカウント+ = AMOUNT [します]。 System.out.printf( "トータルバランス:%N-%10.2f"、getTotalBalance()); sufficientFunds.signalAll(); //メソッドの条件の呼び出しがブロック解除待機スレッドオブジェクトsignalAll } 最後に { bankLock.unlock( ); //ロック解除 } } / ** *すべての口座残高の合計を取得します * @returnトータルバランス * / 公共ダブルgetTotalBalance() { bankLock.lock(); //ロック 試し { ダブル合計= 0; のために(ダブルA:アカウント) SUM = A +; 戻りSUM; } 最後に { bankLock.unlock(); //ロック解除 } } / ** *取得銀行はでコンパイルアカウント。 アカウントの* @return数 * / 公共int型のサイズ() { 戻りaccounts.length。 } }
次のようにプログラムのスクリーンショットの結果は以下のとおりです。
試験手順 2 :
リットル で Elipse デバッグ教育環境 655 ポケットベル 14-8 、プログラムのプログラムを理解を合わせた結果、
マスター同期マルチスレッド同期のアプリケーションを。
次のようにBank.javaコードは次のとおりです。
package synch2; import java.util.*; /** * 使用同步原理的具有多个银行帐户的银行 * @version 1.30 2004-08-01 * @author Cay Horstmann */ public class Bank { private final double[] accounts; /** * 构建了银行 * @param 账户数量 * @param 每个账户的初始余额 */ public Bank(int n, double initialBalance) { accounts = new double[n]; Arrays.fill(accounts, initialBalance); } /** * 把钱从一个账户转到另一个账户 * @param 从账户转出 * @param 到账转到 * @param 转帐金额 */ //类内方法用synchronized修饰后,该方法为同步方法 public synchronized void transfer(int from, int to, double amount) throws InterruptedException { while (accounts[from] < amount) wait(); System.out.print(Thread.currentThread()); accounts[from] -= amount; System.out.printf(" %10.2f from %d to %d", amount, from, to); accounts[to] += amount; System.out.printf(" Total Balance: %10.2f%n", getTotalBalance()); notifyAll(); //执行notifyAll方法通知所有由于这个同步方法而处于等待的线程结束等待 } /** * 获取所有帐户余额的总和 * @return the total balance */ public synchronized double getTotalBalance() { double sum = 0; for (double a : accounts) sum += a; return sum; } /** * 获取银行中的帐户编号. * @return 账户数量 */ public int size() { return accounts.length; } }
SynchBankTest2.java代码如下:
package synch2; /** * 这个程序展示了多线程如何安全地访问一个数据结构,使用同步方法 * @version 1.31 2015-06-21 * @author Cay Horstmann */ public class SynchBankTest2 { public static final int NACCOUNTS = 100; public static final double INITIAL_BALANCE = 1000; public static final double MAX_AMOUNT = 1000; public static final int DELAY = 10; public static void main(String[] args) { Bank bank = new Bank(NACCOUNTS, INITIAL_BALANCE); for (int i = 0; i < NACCOUNTS; i++) { int fromAccount = i; Runnable r = () -> { try { while (true) { int toAccount = (int) (bank.size() * Math.random()); double amount = MAX_AMOUNT * Math.random(); bank.transfer(fromAccount, toAccount, amount); Thread.sleep((int) (DELAY * Math.random())); } } catch (InterruptedException e) { } }; Thread t = new Thread(r); t.start(); } } }
程序运行结果截图如下:
测试程序3:
l 在Elipse环境下运行以下程序,结合程序运行结果分析程序存在问题;
l 尝试解决程序中存在问题。
class Cbank { private static int s=2000; public static void sub(int m) { int temp=s; temp=temp-m; try { Thread.sleep((int)(1000*Math.random())); } catch (InterruptedException e) { } s=temp; System.out.println("s="+s); } }
class Customer extends Thread { public void run() { for( int i=1; i<=4; i++) Cbank.sub(100); } } public class Thread3 { public static void main(String args[]) { Customer customer1 = new Customer(); Customer customer2 = new Customer(); customer1.start(); customer2.start(); } } |
程序代码如下:
package pro; class Cbank { private static int s=2000; public static void sub(int m) { int temp=s; temp=temp-m; try { Thread.sleep((int)(1000*Math.random())); } catch (InterruptedException e) { } s=temp; System.out.println("s="+s); } } class Customer extends Thread { public void run() { for( int i=1; i<=4; i++) Cbank.sub(100); } } public class Thread3 { public static void main(String args[]) { Customer customer1 = new Customer(); Customer customer2 = new Customer(); customer1.start(); customer2.start(); } }
运行结果截图如下:
其存在问题是:这两个线程是各做各的,互不影响,它们相对执行顺序不确定,其执行顺序不确定性会产生执行结果的不确定性。
(用synchronized关键字)修改程序后代码如下:
package pro; class Cbank { private static int s=2000; public synchronized static void sub(int m) { int temp=s; temp=temp-m; try { Thread.sleep((int)(1000*Math.random())); } catch (InterruptedException e) { } s=temp; System.out.println("s="+s); } } class Customer extends Thread { public void run() { for( int i=1; i<=4; i++) Cbank.sub(100); } } public class Thread3 { public static void main(String args[]) { Customer customer1 = new Customer(); Customer customer2 = new Customer(); customer1.start(); customer2.start(); } }
程序运行结果如下截图所示:
实验2 编程练习
利用多线程及同步方法,编写一个程序模拟火车票售票系统,共3个窗口,卖10张票,程序输出结果类似(程序输出不唯一,可以是其他类似结果)。
Thread-0窗口售:第1张票
Thread-0窗口售:第2张票
Thread-1窗口售:第3张票
Thread-2窗口售:第4张票
Thread-2窗口售:第5张票
Thread-1窗口售:第6张票
Thread-0窗口售:第7张票
Thread-2窗口售:第8张票
Thread-1窗口售:第9张票
Thread-0窗口售:第10张票
程序设计思路:
首先创建一个售票的一个线程组,其有3个线程售票,然后通过传递sellTicketThreadGroud参数给一个新的线程,重写run方法,执行sell方法,其中sell方法是使用 synchronized 关键字来修饰的,其确保在一个时刻只有一个线程可以进入sell方法执行代码。
流程图如下:
程序代码如下:
package track; /** * 使用 synchronized 关键字实现线程同步的售卖火车票的测试类 */ public class SellTickets3 { private static int tickets = 1; // 使用 synchronized 关键字修饰方法,确保某一时刻只有一个线程能够进入该方法中执行代码 protected synchronized static void sell() { if (tickets <= 10) { System.out.println(Thread.currentThread().getName() + "窗口售:第 " + tickets++ + " 张票"); } } public static void startSell() { // 售票线程所在线程组 ThreadGroup sellTicketThreadGroup = new ThreadGroup("sell ticket thread group"); // 开启 3个线程售票 for (int i = 0; i < 3; i++) { // 新建售票线程,并将其加入售票线程组中 new Thread(sellTicketThreadGroup, "Thread-" + (i)) { @Override public void run() { while (tickets > 0) { sell(); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } } }.start(); } } public static void main(String[] args) { SellTickets3.startSell(); } }
运行结果截图如下:
实验总结:
本周学习了同步线程的相关问题,了解了并发多线程的两种解决方法,一种是锁对象,还有一种是synchronized关键字。还有在同步线程中使用wait()、notify()和notifyAll()方法,使用wait()方法使本线程等待,暂时让出CPU的使用权,并允许其它线程使用这个同步方法。线程如果用完同步方法,应当执行notifyAll()方法通知所有由于使用这个同步方法而处于等待的线程结束等待。在本周的学习中,自己对同步线程有所掌握,懂得了同步线程的基本工作原理,同时对老师所讲的理论知识有了很好的理解,在这星期中收获挺大的。