目錄
Thread
改進后的電影院售票出現問題
Thread(Runnable target, String name)
改進電影院售票1
解決執行緒安全問題的基本思想
解決執行緒同步安全問題的第一種方法
改進電影院售票2
解決執行緒同步安全問題的第二種解法:加Lock鎖
Class ReentrantLock
void lock() 加鎖
void unlock() 釋放鎖
改進電影院售票3
執行緒同步案例:共享資料案例(執行緒通信)
死鎖
執行緒組
執行緒池Executors
newFixedThreadPool
創建執行緒的第三種方式
callable
匿名內部類方式使用多執行緒
定時器
Timer
Thread
改進后的電影院售票出現問題
- 問題
相同的票出現多次
CPU的一次操作必須是原子性的
還出現了負數的票
隨機性和延遲導致的
- 注意
執行緒安全問題在理想狀態下,不容易出現,但一旦出現對軟體的影響是非常大的,
Thread(Runnable target, String name)
查看API檔案我們知道:
public Thread(Runnable target,String name)分配一個新的
Thread物件, 此構造具有相同的效果Thread(null, target, name),引數
target- 啟動此執行緒時呼叫其run方法的物件, 如果null,則呼叫此執行緒的run方法,
name- 新執行緒的名稱
改進電影院售票1
創建TicketWindow1類:
public class TicketWindow1 implements Runnable{
//定義100張票
private int tickets = 100;
private Object obj = new Object();
@Override
public void run() {
while (true){
synchronized (obj){
if (tickets > 0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "張票");
}
}
}
}
}
創建SellTicketDemo1實作類:
public class SellTicketDemo1 {
public static void main(String[] args) {
TicketWindow1 ticketWindow1 = new TicketWindow1();
//創建執行緒物件模擬3個視窗,并給執行緒起名字
Thread t1 = new Thread(ticketWindow1, "視窗1");
Thread t2 = new Thread(ticketWindow1, "視窗2");
Thread t3 = new Thread(ticketWindow1, "視窗3");
t1.start();
t2.start();
t3.start();
}
}
運行結果:

由于博主的CPU太過強大,多次嘗試后這里沒有出現預想的結果,
解決執行緒安全問題的基本思想
首先想為什么出現問題?(也是我們判斷是否有問題的標準)
- 是否是多執行緒環境
- 是否有共享資料
- 是否有多條陳述句操作共享資料
如何解決多執行緒安全問題呢?
- 基本思想:讓程式沒有安全問題的環境
- 怎么實作呢?
把多個陳述句操作共享資料的代碼給鎖起來,讓任意時刻只能有一個執行緒執行即可,
同步代碼塊
格式:
synchronized(物件){需要同步的代碼;
}
同步可以解決安全問題的根本原因就在那個物件上,該物件如同鎖的功能,
同步代碼塊的鎖物件是誰呢?
任意物件,但是多個執行緒之間鎖物件要一樣
同步方法的鎖物件是誰呢?
將synchronized關鍵字放到方法上 同步方法的鎖物件是this
靜態方法的鎖物件是誰呢? class檔案,位元組碼檔案物件也是屬于一個Object類下面的物件,這個class檔案不能是隨便一個類的位元組碼檔案應該是run方法所在類的位元組碼檔案
解決執行緒同步安全問題的第一種方法
改進電影院售票2
創建TicketWindow2類:
public class TicketWindow2 implements Runnable {
//定義1000張票
private static int tickets = 1000;
int i = 1;
@Override
public void run() {
while (true){
if (i%2==0){
synchronized (TicketWindow2.class){
if (tickets > 0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "張票");
}
}
}else {
sellTicket();
}
}
}
private synchronized static void sellTicket() {
if (tickets > 0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "張票");
}
}
}
創建SellTicketDemo2實作類:
public class SellTicketDemo2 {
public static void main(String[] args) {
TicketWindow2 ticketWindow2 = new TicketWindow2();
Thread t1 = new Thread(ticketWindow2, "視窗1");
Thread t2 = new Thread(ticketWindow2, "視窗2");
Thread t3 = new Thread(ticketWindow2, "視窗3");
t1.start();
t2.start();
t3.start();
}
}
運行結果:

從運行結果上來看我們實作了執行緒的安全,
解決執行緒同步安全問題的第二種解法:加Lock鎖
Class ReentrantLock
查看API檔案我們知道:
public class ReentrantLock extends Object implements Lock, Serializable一個可重入互斥
Lock具有與使用synchronized方法和陳述句訪問的隱式監視鎖相同的基本行為和語意,但具有擴展功能,A
ReentrantLock由執行緒擁有 ,最后成功鎖定,但尚未解鎖, 呼叫lock的執行緒將回傳,成功獲取鎖,當鎖不是由另一個執行緒擁有, 如果當前執行緒已經擁有該鎖,該方法將立即回傳, 這可以使用方法isHeldByCurrentThread()和getHoldCount()進行檢查,該類的建構式接受可選的公平引數, 當設定
true,在爭用下,鎖有利于授予訪問最長等待的執行緒, 否則,該鎖不保證任何特定的訪問順序, 使用許多執行緒訪問的公平鎖的程式可能會比使用默認設定的整體吞吐量(即,更慢,通常要慢得多),但是具有更小的差異來獲得鎖定并保證缺乏饑餓, 但是請注意,鎖的公平性不能保證執行緒調度的公平性, 因此,使用公平鎖的許多執行緒之一可以連續獲得多次,而其他活動執行緒不進行而不是當前持有鎖, 另請注意, 未定義的tryLock()方法不符合公平性設定, 如果鎖可用,即使其他執行緒正在等待,它也會成功,建議的做法是始終立即跟隨
lock與try塊的通話,最常見的是在之前/之后的建設,如:class X { private final ReentrantLock lock = new ReentrantLock(); // ... public void m() { lock.lock(); // block until condition holds try { // ... method body } finally { lock.unlock() } } }除了實作
Lock介面,這個類定義了許多public種protected方法用于檢查鎖的狀態, 其中一些方法僅適用于儀器和監控,此類的序列化與內置鎖的操作方式相同:反序列化鎖處于未鎖定狀態,無論其序列化時的狀態如何,
此鎖最多支持同一個執行緒的2147483647遞回鎖, 嘗試超過此限制會導致
Error從鎖定方法中拋出,
void lock() 加鎖
查看API檔案我們知道:
public void lock()獲得鎖,
如果鎖沒有被另一個執行緒占用并且立即回傳,則將鎖定計數設定為1,
如果當前執行緒已經保持鎖定,則保持計數增加1,該方法立即回傳,
如果鎖被另一個執行緒保持,則當前執行緒將被禁用以進行執行緒調度,并且在鎖定已被獲取之前處于休眠狀態,此時鎖定保持計數被設定為1,
Specified by:
lock在界面Lock
void unlock() 釋放鎖
查看API檔案我們知道:
public void unlock()嘗試釋放此鎖,
如果當前執行緒是該鎖的持有者,則保持計數遞減, 如果保持計數現在為零,則鎖定被釋放, 如果當前執行緒不是該鎖的持有者,則拋出
IllegalMonitorStateException,Specified by:
unlock在界面Lock例外
IllegalMonitorStateException- 如果當前執行緒不持有此鎖
在此之前我們解決執行緒同步安全問題的時候,使用的是synchronized關鍵字,通過分析然后將哪些代碼塊給包起來,但是我們并沒有直接看到在哪里上了鎖,或者說在哪里釋放了鎖讓其它執行緒獲取到,為了更加清晰的表達如何加鎖以及如何釋放鎖,JDK1.5之后提供了一個新的鎖物件Lock,
改進電影院售票3
創建TicketWindow3類:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TicketWindow3 implements Runnable {
//定義100張票
private int tickets = 100;
//創建鎖物件
Lock lock = new ReentrantLock();
@Override
public void run() {
while (true){
lock.lock();
if (tickets > 0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在售出第" + (tickets--) + "張票");
}
lock.unlock();
}
}
}
創建SellTicketDemo3實作類:
public class SellTicketDemo3 {
public static void main(String[] args) {
TicketWindow3 ticketWindow3 = new TicketWindow3();
Thread t1 = new Thread(ticketWindow3, "視窗1");
Thread t2 = new Thread(ticketWindow3, "視窗2");
Thread t3 = new Thread(ticketWindow3, "視窗3");
t1.start();
t2.start();
t3.start();
}
}
運行結果:

執行緒同步案例:共享資料案例(執行緒通信)
創建Student類:
public class Student {
String name;
int age;
boolean flag;
}
創建自定義類GetThread:
import java.util.concurrent.locks.Lock;
public class GetThread implements Runnable {
private Student s;
private Lock lock;
public GetThread(Student student) {
this.s = student;
}
public GetThread(Student student, Lock lock) {
this.s = student;
this.lock = lock;
}
@Override
public void run() {
while (true){
synchronized (s){
//判斷學生物件有沒有值
//如果flag的值是false,說明沒有資料,消費者進if判斷等待
if(!s.flag){
try {
s.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(s.name + "---" + s.age);
//消費者消費完資料后通知生產者生產資料
s.notify();
s.flag = false;
}
}
}
}
創建自定義類SetThread類:
import java.util.concurrent.locks.Lock;
public class SetThread implements Runnable{
private Student s;
private int i = 0;
private Lock lock;
public SetThread(Student student) {
this.s = student;
}
public SetThread(Student student, Lock lock) {
this.s = student;
this.lock = lock;
}
@Override
public void run() {
while (true){
synchronized (s){
//判斷學生物件有沒有值
//flag初始的時候是flase,表示沒有值,如果是true表示學生物件有值
//有值對于生產者來說,等待消費者消費
if(s.flag){
try {
s.wait(); //呼叫wait(),執行緒阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(i%2==0){
s.name = "劉德華";
s.age = 65;
}else {
s.name = "張學友";
s.age = 73;
}
i++;
//生產者生產完資料之后通知消費者消費資料
s.notify();
s.flag = true;
}
}
}
}
創建實作類:StudentDemo
public class StudentDemo {
public static void main(String[] args) {
//創建共享的學生物件
Student student = new Student();
//創建自定義類物件
SetThread setThread = new SetThread(student);
GetThread getThread = new GetThread(student);
//根據Runnable的物件創建生產者和消費者的執行緒物件
Thread proThread = new Thread(setThread);
Thread cusThread = new Thread(getThread);
cusThread.start();
proThread.start();
}
}
運行結果:

分析:
共享資料:Student 生產者:SetThread 給學生的成員變數進行賦值操作 消費者:GetThread 獲取學生的成員變數的資訊 測驗類:StudentDemo 創建執行緒并測驗在寫這個案例之前我們將會遇到一些問題可能是以下原因導致的
CPU一點點的時間片就足矣執行很多次
執行緒執行的時候具有隨機性導致的
注意事項: 1、不同種類的執行緒類都要加鎖 2、不用種類的執行緒類中的鎖物件要一樣 問題3:雖然我們解決執行緒安全問題,但是經過分析,程式還存在著等待喚醒機制的問題, 加入等待喚醒機制, 如何添加等待喚醒機制呢? Object類中有三個方法: void wait() 導致當前執行緒等待,直到另一個執行緒呼叫該物件的 notify()方法或 notifyAll()方法, void notify() 喚醒正在等待物件監視器的單個執行緒, void notifyAll() 喚醒正在等待物件監視器的所有執行緒, 這三個方法為什么不定義再Thread類中呢? 這些方法想要呼叫,必須通過鎖的物件呼叫,而我們直到同步代碼塊的鎖物件可以是任意物件 所以這些方法都在Object類中,因為java中所有類的父類都是Object
既然實作了執行緒的共享,那么如果出現了同步嵌套,就容易產生死鎖問題
死鎖
死鎖是指兩個或者兩個以上的執行緒在執行的程序中,因爭奪資源產生的一種互相等待現象
參考代碼:
創建DieLock類:
public class DieLock extends Thread {
private boolean flag;
public DieLock(boolean flag){
this.flag = flag;
}
/* 現象1:
if lock1
else lock2
現象2:
else lock2
if lock1
*/
@Override
public void run() {
if(flag){
//d1
synchronized (MyLock.lock1){
System.out.println("if lock1");
//d1
synchronized (MyLock.lock2){
System.out.println("if lock2");
}
}
}else {
//d2
synchronized (MyLock.lock2){
System.out.println("else lock2");
//d2
synchronized (MyLock.lock1){
System.out.println("else lock1");
}
}
}
}
}
創建實作類DieLockDemo:
public class DieLockDemo {
public static void main(String[] args) {
DieLock d1 = new DieLock(true);
DieLock d2 = new DieLock(false);
d1.start();
d2.start();
}
}
運行結果:
if lock1
else lock2
else lock2
if lock1
在我們今后的開發中要避免鎖的同步嵌套使用,不然就很容易產生死鎖問題
執行緒組
查看API檔案我們知道:
public Thread(ThreadGroup group,Runnable target,String name)分配一個新的
Thread物件,使其具有target作為其運行物件,具有指定的name作為其名稱,屬于group參考的執行緒組,如果有安全管理器,則使用ThreadGroup作為引數呼叫其
checkAccess方法,此外,它的
checkPermission方法由RuntimePermission("enableContextClassLoaderOverride")權限呼叫,直接或間接地由覆寫getContextClassLoader或setContextClassLoader方法的子類的getContextClassLoadersetContextClassLoader呼叫,新創建的執行緒的優先級設定為等于創建執行緒的優先級,即當前正在運行的執行緒, 可以使用方法setPriority將優先級改變為新值,
當且僅當創建它的執行緒當前被標記為守護執行緒時,新創建的執行緒才被初始化為守護執行緒, 方法setDaemon可以用于改變執行緒是否是守護行程,
引數
group- 執行緒組, 如果是null并且有一個安全管理器,則該組由SecurityManager.getThreadGroup()決定 , 如果沒有安全管理員或SecurityManager.getThreadGroup()回傳null,該組將設定為當前執行緒的執行緒組,
target- 啟動此執行緒時呼叫其run方法的物件, 如果null,則呼叫此執行緒的run方法,
name- 新執行緒的名稱例外
SecurityException- 如果當前執行緒不能在指定的執行緒組中創建執行緒,或者不能覆寫背景關系類加載器方法,
Java中使用ThreadGroup來表示執行緒組,它可以對一批執行緒進行分類管理, Java允許程式直接對執行緒組進行控制,
參考代碼:
創建MyRunnable類:
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
創建實作類ThreadGroupDemo:
public class ThreadGroupDemo {
public static void main(String[] args) {
//創建自定義類物件
MyRunnable myRunnable = new MyRunnable();
//創建執行緒物件
Thread t1 = new Thread(myRunnable, "劉德華");
Thread t2 = new Thread(myRunnable, "張學友");
//我們之前都沒有提過執行緒組,以及分組的概念,想著應該有一個默認的分組
//獲取分組
//ThreadGroup getThreadGroup()
//回傳此執行緒所屬的執行緒組,
ThreadGroup tg1 = t1.getThreadGroup();
System.out.println(tg1);
ThreadGroup tg2 = t2.getThreadGroup();
System.out.println(tg2);
//獲取執行緒組的名字
//String getName()
//回傳此執行緒組的名稱,
System.out.println(tg1.getName());
System.out.println(tg2.getName());
System.out.println(Thread.currentThread().getName());
//需求:給執行緒分組
//Thread(ThreadGroup group, Runnable target, String name)
//分配一個新的 Thread物件,使其具有 target作為其運行物件,
// 具有指定的 name作為其名稱,屬于 group參考的執行緒組,
//創建一個新的執行緒組
//ThreadGroup(String name)
//構造一個新的執行緒組,
ThreadGroup tg3 = new ThreadGroup("下路三人組");
//創建執行緒物件
Thread t3 = new Thread(tg3, myRunnable, "榮耀行刑官");
Thread t4 = new Thread(tg3, myRunnable, "魂鎖典獄長");
Thread t5 = new Thread(tg3, myRunnable, "蒸汽機器人");
System.out.println(t3.getThreadGroup().getName());
System.out.println(t4.getThreadGroup().getName());
//Java允許程式直接對執行緒組進行控制
//直接通過組名設定這一組都是守護執行緒,組里面的執行緒都是守護執行緒
tg3.setDaemon(true);
}
}
運行結果:
java.lang.ThreadGroup[name=main,maxpri=10]
java.lang.ThreadGroup[name=main,maxpri=10]
main
main
main
下路三人組
下路三人組
執行緒池Executors
newFixedThreadPool
查看API檔案我們知道:
public static ExecutorService newFixedThreadPool(int nThreads)創建一個執行緒池,該執行緒池重用固定數量的從共享無界佇列中運行的執行緒, 在任何時候,最多
nThreads執行緒將處于主動處理任務, 如果所有執行緒處于活動狀態時都會提交其他任務,則它們將等待佇列中直到執行緒可用, 如果任何執行緒由于在關閉之前的執行期間發生故障而終止,則如果需要執行后續任務,則新執行緒將占用它, 池中的執行緒將存在,直到它明確地為shutdown,引數
nThreads- 池中的執行緒數結果
新創建的執行緒池
例外
IllegalArgumentException- 如果是nThreads <= 0
程式啟動一個新執行緒成本是比較高的,因為它涉及到要與作業系統進行互動,
而使用執行緒池可以很好的提高性能,尤其是當程式中要創建大量生存期很短的執行緒時, 更應該考慮使用執行緒池, 執行緒池里的每一個執行緒代碼結束后,并不會死亡,而是再次回到執行緒池中成為空閑狀態, 等待下一個物件來使用, 在JDK5之前,我們必須手動實作自己的執行緒池,從JDK5開始,Java內置支持執行緒池 如何實作執行緒池的代碼呢? 1、創建執行緒池物件,Executors工廠類下的靜態方法 newFixedThreadPool是其中一種執行緒池 public static ExecutorService newFixedThreadPool(int nThreads) 2、如何往執行緒池中存放執行緒?(可以存放哪些執行緒呢?) 3、在執行緒池中的執行緒如何運行呢? 4、我想結束執行緒的運行,可不可以手動結束呢?如果可以,怎么結束?
參考代碼1:
public class ThreadPoolDemo {
public static void main(String[] args) {
//創建執行緒池
ExecutorService pool = Executors.newFixedThreadPool(2);
//Future<?> submit(Runnable task)
//提交一個可運行的任務執行,并回傳一個表示該任務的未來,
MyRunnable myRunnable = new MyRunnable();
pool.submit(myRunnable);
pool.submit(myRunnable);
//提交數超過執行緒池的數量的時候也會執行,只不過是當有空閑執行緒位置的時候再去執行
//newFixedThreadPool最大一次性可執行執行緒數量為初始設定的數量
pool.submit(myRunnable);
//我想結束執行緒的運行,可不可以手動結束呢?如果可以,怎么結束?
//void shutdown()
//啟動有序關閉,其中先前提交的任務將被執行,但不會接受任何新任務,
pool.shutdown();
System.out.println("======================================");
//RejectedExecutionException
//執行緒池已經被關閉了,不能再提交任務執行
pool.submit(myRunnable);
}
}
運行結果:

提交數超過執行緒池的數量的時候也會執行,只不過是當有空閑執行緒位置的時候再去執行newFixedThreadPool最大一次性可執行執行緒數量為初始設定的數量
創建執行緒的第三種方式
callable
查看API檔案我們知道:
public static Callable<Object> callable(PrivilegedExceptionAction<?> action)回傳一個
Callable物件,該物件在被呼叫時運行給定的特權例外操作并回傳其結果,引數
action- 運行的特權例外操作結果
可呼叫物件
例外
NullPointerException- 如果動作為空
參考代碼2:
創建自定義類MyCallable:
import java.util.concurrent.Callable;
public class MyCallable implements Callable {
@Override
public Object call() throws Exception {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "---" + i);
}
return null;
}
}
創建實作類ThreadPoolDemo2:
public class ThreadPoolDemo2 {
public static void main(String[] args) {
//創建執行緒池物件
ExecutorService pool = Executors.newFixedThreadPool(2);
MyRunnable myRunnable = new MyRunnable();
MyCallable myCallable = new MyCallable();
//可以執行Runnable物件或者Callable物件代表的執行緒池
pool.submit(myRunnable);
pool.submit(myCallable);
pool.shutdown();
}
}
運行結果:

匿名內部類方式使用多執行緒
參考代碼:
public class ThreadDemo2 {
public static void main(String[] args) {
Thread t1 = new Thread("靚仔"){
@Override
public void run() {
for (int i = 0;i < 100;i++){
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
};
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0;i < 100;i++){
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
},"劉德華");
t2.start();
}
}
運行結果:

定時器
定時器是一個應用十分廣泛的執行緒工具,可用于調度多個定時任務以后臺執行緒的方式執行,在Java中,可以通過Timer和TimerTask類來實作定義調度的功能,
Timer
查看API檔案我們知道:
public class Timer extends Object執行緒調度任務以供將來在后臺執行緒中執行的功能, 任務可以安排一次執行,或定期重復執行,
對應于每個Timer物件是單個后臺執行緒,用于依次執行所有定時器的所有任務, 計時器任務應該快速完成, 如果一個定時器任務需要花費很多時間來完成,它會“計時”計時器的任務執行執行緒, 這可能會延遲隨后的任務的執行,這些任務在(和)如果違規任務最后完成時,可能會“束起來”并快速執行,
在最后一次對Timer物件的參考后,所有未完成的任務已完成執行,定時器的任務執行執行緒正常終止(并被收集到垃圾回收), 但是,這可能需要任意長時間的發生, 默認情況下,任務執行執行緒不作為守護程式執行緒運行,因此它能夠使應用程式終止, 如果主叫方想要快速終止定時器的任務執行執行緒,則呼叫者應該呼叫定時器的cancel方法,
如果定時器的任務執行執行緒意外終止,例如,因為它呼叫了stop方法,那么在計時器上安排任務的任何進一步的嘗試將會產生一個IllegalStateException ,就像定時器的cancel方法被呼叫一樣,
這個類是執行緒安全的:多個執行緒可以共享一個單獨的Timer物件,而不需要外部同步,
此類不提供實時保證:使用Object.wait(long)方法是調度任務,
Java 5.0引入了
java.util.concurrent軟體包,其中一個java.util.concurrent程式是ScheduledThreadPoolExecutor,它是用于以給定速率或延遲重復執行任務的執行緒池, 這實際上是對一個更靈活的替代Timer/TimerTask組合,因為它允許多個服務執行緒,接受各種時間單位,并且不需要子類TimerTask(只實作Runnable), 使用一個執行緒配置ScheduledThreadPoolExecutor使其等同于Timer,實作注意事項:這個類可以擴展到大量并發計劃任務(千應該沒有問題), 在內部,它使用二進制堆表示其任務佇列,因此計劃任務的成本為O(log n),其中n為并發計劃任務的數量,
實作注意事項:所有建構式啟動計時器執行緒,
參考代碼1:
public class TimerDemo {
public static void main(String[] args) {
//創建定時器物件
//Timer()
//創建一個新的計時器,
Timer timer = new Timer();
//調度任務執行
//在指定的延遲之后安排指定的任務執行, 定時在未來的某一時刻執行任務
//public void schedule(TimerTask task, long delay)
//自定義子類的形式創建任務
//delay這個型別是毫秒
timer.schedule(new MyTask(timer), 3000);
//public void cancel()終止此計時器,丟棄任何當前計劃的任務
//timer.cancel();
// timer.schedule(new MyTask(timer), 3000);
}
}
class MyTask extends TimerTask{
private Timer timer;
public MyTask(Timer timer){
this.timer = timer;
}
@Override
public void run() {
System.out.println("靚仔真帥");
timer.cancel();
}
}
運行結果:
靚仔真帥
參考代碼2:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
public class TimerDemo2 {
public static void main(String[] args) {
//創建定時器物件
Timer timer = new Timer();
//void schedule(TimerTask task, long delay, long period)
//在指定的延遲之后開始 ,重新執行 固定延遲執行的指定任務,
//3秒后執行任務,并且每個2秒執行一次任務
timer.schedule(new MyTask2(),3000,2000);
}
}
class MyTask2 extends TimerTask{
@Override
public void run() {
try {
FileReader fr = new FileReader("src\\liangzai.txt");
BufferedReader br = new BufferedReader(fr);
System.out.println(br.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
}
運行結果:

通過觀察運行結果發現,3秒后輸出靚仔真帥!,之后每兩秒輸出一次靚仔真帥!
到底啦!給靚仔一個關注吧!? つ ?_? ?つ
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/398606.html
標籤:其他
