java-多线程操作全(Thread)-Timer简单使用
?一、 多線程概念和作用
?線程指進(jìn)程中的一個(gè)執(zhí)行場(chǎng)景,也就是執(zhí)行流程,那么進(jìn)程和線程的區(qū)別是什么
? 1.每個(gè)進(jìn)程是一個(gè)應(yīng)用程序,都有獨(dú)立的內(nèi)存空間
? 2.同一個(gè)進(jìn)程中的線程共享其進(jìn)程中的內(nèi)存和資源
? (共享的內(nèi)存是堆內(nèi)存和方法內(nèi)存,棧內(nèi)存不共享,每個(gè)線程有自己的堆內(nèi)存)
?進(jìn)程:進(jìn)程對(duì)應(yīng)一個(gè)應(yīng)用程序
? 現(xiàn)在的計(jì)算機(jī)都是支持多進(jìn)程的,在同一個(gè)操作系統(tǒng)中,可以同時(shí)啟動(dòng)多個(gè)進(jìn)程?
??
?多進(jìn)程的作用:
?* 單進(jìn)程只能做一件事 : 一邊玩游戲,一邊聽音樂不是同時(shí)運(yùn)行,而是進(jìn)程之間的頻繁調(diào)度,切換速度極高,感覺是同時(shí)進(jìn)行。
?* 多線程的作用不是提高執(zhí)行速度,而是提高CPU的使用率。進(jìn)程和進(jìn)程之間的內(nèi)存是獨(dú)立的、
?* 線程:是進(jìn)程中的執(zhí)行場(chǎng)景。一個(gè)進(jìn)程可以啟動(dòng)多個(gè)線程。
?* 多線程的作用:不是為了提高執(zhí)行速度,而是為了提高應(yīng)用程序的使用率
?
?* java程序的運(yùn)行原理
?* java命令啟動(dòng)java虛擬機(jī),啟動(dòng)JVM,等于啟動(dòng)一個(gè)應(yīng)用程序,表明啟動(dòng)一個(gè)進(jìn)程。該進(jìn)程會(huì)自動(dòng)啟動(dòng)一個(gè)“主線程”,然后主線程去調(diào)用某各類的main方法。
?* 所以,main方法運(yùn)行在主線程中。在此之前的所有程序都是單線程的。
?
?二、線程的創(chuàng)建和啟動(dòng)
?
?*Java虛擬機(jī)的主線程入口是main方法,用戶可以自己創(chuàng)建線程,創(chuàng)建方式有兩種
?*1.繼承Thread類
?*2.實(shí)現(xiàn)Runnable接口(推薦使用Runnable)
?
?*繼承Thread類
?*采用 Thread類創(chuàng)建線程,用戶只需要繼承 Thread,覆蓋 Thread中的run方法,父類 Thread中的run方法沒有拋出異常,那么子類也不角能拋出異常,最后采用start啟動(dòng)線程即可
?
?實(shí)現(xiàn)Runnable接口
?Thread對(duì)象本身就實(shí)現(xiàn)了 Runnable接口,但一般建議直接使用 Runnable接口來寫多線程程序,因?yàn)榻涌跁?huì)比類帶來更多的好處
?
三、java語言中實(shí)現(xiàn)多線程第一種方式
?
1.繼承java.lang.Thread
2.重寫run方法
三個(gè)知識(shí)點(diǎn) :定義線程 、創(chuàng)建線程、?啟動(dòng)線程
package com.steven.demo;import java.lang.Thread; public class ThreadTest {public static void main(String[] args) {Thread thread = new Student();//啟動(dòng)線程thread.start();//打印Run:0~9//start方法執(zhí)行完瞬間結(jié)束,告訴JVM再分配一個(gè)新的線程 給t線程//是隨機(jī)分配的,沒有規(guī)律//run不需要手動(dòng)調(diào)用,系統(tǒng)程序啟動(dòng)之后會(huì)自動(dòng)調(diào)用方法//thread.run();//這是普通方法的調(diào)用,這樣做程序只有一個(gè)線程,run方法結(jié)束之后,下邊的程序才會(huì)執(zhí)行for (int i = 0; i < 5; i++) {System.out.println("main"+i);}//有了多線程之后,main方法結(jié)束只是主線程中沒有方法棧幀了 但是其他線程或者其他棧中還有棧幀 main方法結(jié)束,程序可能還在運(yùn)行 } }class Student extends Thread {//重寫Run方法public void run() {for (int i = 0; i < 10; i++) {System.out.println("Run:"+i);}} }四、java語言中實(shí)現(xiàn)多線程第二種方式
1.寫一個(gè)類實(shí)現(xiàn)
2.重寫run方法
?
package com.steven.demo;import java.lang.Runnable; import java.lang.Thread; public class ThreadTest02 {public static void main(String[] args) {//創(chuàng)建線程:Thread thread = new Thread(new Teacher());//啟動(dòng)線程 thread.start();} } class Teacher implements Runnable {//重寫Run方法public void run() {for (int i = 0; i < 10; i++) {System.out.println("Run:"+i);}} }五、掌握線程方法:
1.獲取當(dāng)前線程的對(duì)象 Thread.currentThread()
2.給線程起名t.setName()
3.獲取線程的名字:t.getName()
?
package com.steven.demo; public class ThreadTest03 {public static void main(String[] args) {//獲取當(dāng)前線程的對(duì)象 main主線程Thread thread = Thread.currentThread();//獲取當(dāng)前線程的名字System.out.println("當(dāng)前名稱的名稱"+thread.getName());//當(dāng)前名稱的名稱main Thread t1 = new Thread(new ArrayTest());//給線程起名t1.setName("Steven");t1.start();//線程的名稱Steven Thread thread2 = new Thread(new ArrayTest());//給線程重命名thread2.setName("珂珂");thread2.start();//線程的名稱珂珂 } } class ArrayTest implements Runnable {public void run() {Thread thread = Thread.currentThread();//獲取當(dāng)前線程的對(duì)象System.out.println("線程的名稱"+thread.getName());} }六、線程的優(yōu)先級(jí)
優(yōu)先級(jí)高的獲取CPU時(shí)間片,相對(duì)多一些
最高:10
最小:1
默認(rèn):5
優(yōu)先級(jí)1-10
優(yōu)先級(jí)高的線程,會(huì)得到CPU的時(shí)間多一些,優(yōu)先執(zhí)行完成
?
public class ThreadTest04 {public static void main(String[] args) {System.out.println("最高"+Thread.MAX_PRIORITY);System.out.println("最小"+Thread.MIN_PRIORITY);System.out.println("默認(rèn)"+Thread.NORM_PRIORITY);Thread t1 = new Thread(new KeKe());t1.setName("t1");Thread t2 = new Thread(new KeKe());t2.setName("t2");//獲取線程的優(yōu)先級(jí)System.out.println("t1優(yōu)先級(jí)"+t1.getPriority());System.out.println("t2優(yōu)先級(jí)"+t2.getPriority());//設(shè)置優(yōu)先級(jí)t1.setPriority(5);t2.setPriority(6);//啟動(dòng) t1.start();t2.start();//線程雖然有優(yōu)先級(jí),但是隨機(jī)分配的,打印結(jié)果不一致 } } class KeKe extends Thread {public void run() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName()+"----------------"+i);}} }七、線程休眠
①Thread.sleep()使當(dāng)前正在執(zhí)行的線程執(zhí)行休眠操作(暫停執(zhí)行) 單位:毫秒
sleep 靜態(tài)方法 作用: 阻塞當(dāng)前線程,騰出CPU,讓給其他線程
public class ThreadTest05 {public static void main(String[] args) {Thread thread = new Array1();thread.setName("thread1");thread.start();//獲取當(dāng)前線程的對(duì)象 main主線程Thread t = Thread.currentThread();//獲取當(dāng)前線程的名字System.out.println("當(dāng)前名稱的名稱"+t.getName());//當(dāng)前名稱的名稱main //阻塞主線程for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + "-------------------:" + i);try {Thread.sleep(2000);//程序休眠2秒鐘} catch (InterruptedException e) {// TODO Auto-generated catch block e.printStackTrace();}}} } class Array1 extends Thread {public void run() {System.out.println("線程正在啟動(dòng)=-====");for (int i = 0 ; i < 5 ; i ++) {System.out.println(Thread.currentThread().getName() + "-------------------:" + i);try {Thread.sleep(2000);//程序休眠2秒鐘} catch (InterruptedException e) {// TODO Auto-generated catch block e.printStackTrace();}}} }②Thread.yield()暫停當(dāng)前正在執(zhí)行的線程對(duì)象,并執(zhí)行其他線程。
?1.靜態(tài)方法
?2.作用:給同一個(gè)優(yōu)先級(jí)的線程讓位,但是讓位時(shí)間不固定
?3.和sleep方法相同,就是yield的時(shí)間不固定
?他與sleep類似,只是不能由用戶執(zhí)行暫停時(shí)間,并且yield()只能讓同優(yōu)先級(jí)的線程有執(zhí)行的機(jī)會(huì)
?
package com.steven.demo; public class ThreadTest07 {public static void main(String[] args) {//1.創(chuàng)建線程Thread thread = new HThread();thread.setName("線程07");//2.啟動(dòng)線程 thread.start();//3.主線程for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() +"---------:"+i);}System.out.println("Steven=====");} } class HThread extends Thread {public void run() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() +"---------:"+i);if (i % 2 == 0) {//暫定當(dāng)前線程,執(zhí)行其他線程 Thread.yield();}}} }③線程的基本操作
/*線程的基本操作:創(chuàng)建,啟動(dòng),休眠,異常處理*/ public class ThreadTest06 {public static void main(String[] args) {try {//1.創(chuàng)建線程Thread thread = new MyThread();thread.setName("線程");//2.啟動(dòng)線程 thread.start();//3.休眠Thread.sleep(2000);System.out.println("Steven=====");}catch (InterruptedException e) {e.printStackTrace();} } }class MyThread extends Thread {public void run() {for (int i = 0; i < 10; i++) {try {Thread.sleep(3000);} catch (Exception e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() +"---------:"+i);}} }八、線程的合并(join)
public class ThreadTest08 {public static void main(String[] args) {try {//1.創(chuàng)建線程Thread thread = new KThread();thread.setName("線程07");//2.啟動(dòng)線程 thread.start();//3.合并線程 (線程07和main線程合并)thread.join();//輸出只保證一個(gè)線程正在執(zhí)行,依次執(zhí)行,單線程的程序 (先執(zhí)行線程07后執(zhí)行main)//主線程for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() +"---------:"+i);} //當(dāng)前線程可以調(diào)用第一個(gè)線程的join方法,調(diào)用后當(dāng)前線程會(huì)被阻塞不再執(zhí)行,直到被調(diào)用的線程執(zhí)行完畢,當(dāng)前線程才會(huì)執(zhí)行} catch (InterruptedException e) {// TODO Auto-generated catch block e.printStackTrace();}} } class KThread extends Thread {public void run() {for (int i = 0; i < 10; i++) {try {Thread.sleep(2000);System.out.println(Thread.currentThread().getName() +"---------:"+i);} catch (InterruptedException e) {// TODO Auto-generated catch block e.printStackTrace();};}} }九、線程同步案例
<1>模擬取款:(不使用同步機(jī)制)多線程同時(shí)對(duì)同一個(gè)賬號(hào)進(jìn)行取款操作
?
/* 模擬取款:不使用同步機(jī)制,多線程同時(shí)對(duì)同一個(gè)賬號(hào)進(jìn)行取款操作 thread 和 thread2 異步編程模型:thread線程執(zhí)行的是thread , thread2線程執(zhí)行的是thread2 ,兩個(gè)線程之間誰也不等于誰 同步編程模型:thread線程和thread2線程執(zhí)行,當(dāng)thread線程必須等thread2的線程的執(zhí)行結(jié)果之后,thread線程才能執(zhí)行 ,這是同步編程什么時(shí)候需要引入同步: 1.為了數(shù)據(jù)安全,盡管程序的使用率低,但是為了保證數(shù)據(jù)安全性,必須得加入線程同步機(jī)制, 線程同步機(jī)制 使程序變成了單線程(一個(gè)線程) 2.在什么條件下需要使用線程同步 <1>必須是多線程環(huán)境 <2>多線程環(huán)境在共享同一個(gè)數(shù)據(jù)時(shí) <3>共享的數(shù)據(jù)涉及到修改操作*/ package com.steven.demo;public class ThreadTest09 {public static void main(String[] args) {//創(chuàng)建一個(gè)公共的賬戶Account account = new Account("steven_kou",10000.0);//創(chuàng)建線程對(duì)同一個(gè)賬戶進(jìn)行取款Thread thread = new Thread(new Money(account));thread.setName("steven");Thread thread2 = new Thread(new Money(account));thread2.setName("kou");thread.start();thread2.start();} }//取款線程 class Money implements Runnable {//賬戶 Account account;Money (Account account){this.account = account;}public void run() {account.withDraw(2000.0);System.out.println("取款2000.0$,余額為:"+account.getBalance());//取款2000.0$,余額為:8000.0 (輸出兩次) }}//銀行賬戶 class Account {private String actno;private double balance;//賬戶余額public Account() {}public Account(String actno,double balance) {this.actno = actno;//成員變量|局部變量this.balance = balance;}public void setActno(String actno) {this.actno = actno;}public String getActno() {return actno;}public void setBalance(double balance) {this.balance = balance;}public double getBalance() {return balance;}//對(duì)外提供一個(gè)取款方法public void withDraw(double money) {//對(duì)賬戶進(jìn)行取款操作double after = balance - money;//延遲操作try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();//InterruptedException 線程中斷下拋出的異常 }this.setBalance(after);//更新賬戶余額,重新賦值 } }<2>模擬取款(同步機(jī)制,同步鎖synchronized)
①以下程序使用線程同步機(jī)制保證數(shù)據(jù)安全
?
package com.steven.demo; public class ThreadTest09 {public static void main(String[] args) {//創(chuàng)建一個(gè)公共的賬戶Account account = new Account("steven_kou",10000.0);//創(chuàng)建線程對(duì)同一個(gè)賬戶進(jìn)行取款Thread thread = new Thread(new Money(account));thread.setName("steven");Thread thread2 = new Thread(new Money(account));thread2.setName("kou");thread.start();thread2.start();} }//取款線程 class Money implements Runnable {//賬戶 Account account;Money (Account account){this.account = account;}public void run() {account.withDraw(2000.0);System.out.println("取款2000.0$,余額為:"+account.getBalance());//取款2000.0$,余額為:8000.0 (輸出兩次) }}//銀行賬戶 class Account {private String actno;private double balance;//賬戶余額public Account() {}public Account(String actno,double balance) {this.actno = actno;//成員變量|局部變量this.balance = balance;}public void setActno(String actno) {this.actno = actno;}public String getActno() {return actno;}public void setBalance(double balance) {this.balance = balance;}public double getBalance() {return balance;}//對(duì)外提供一個(gè)取款方法//TODO 取款 同步public void withDraw(double money) {/*需要把同步的代碼,放到同步的語句塊中thread線程執(zhí)行到此處,遇到了synchronized 關(guān)鍵字,就會(huì)去找this的對(duì)象鎖 如果找到了this的對(duì)象鎖,則進(jìn)入同步語句塊 執(zhí)行程序當(dāng)同步語句塊代碼執(zhí)行結(jié)束的時(shí)候,thread線程歸還this的對(duì)象鎖在thread線程執(zhí)行同步語句塊的過程中,如果thread2線程也執(zhí)行以下代碼。遇到synchronized 關(guān)鍵字,所以去找this對(duì)象鎖,但是該對(duì)象被thread線程持有, 只能等待thread線程使用完以后再解鎖this對(duì)象鎖*///同步鎖synchronized (this) {//對(duì)賬戶進(jìn)行取款操作double after = balance - money;//延遲操作try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();//InterruptedException 線程中斷下拋出的異常 }//更新賬戶余額,重新賦值this.setBalance(after);}} }②synchronized關(guān)鍵字 添加到成員方法上,線程拿走的也是this對(duì)象鎖
//對(duì)外提供一個(gè)取款方法//TODO 取款 同步//synchronized關(guān)鍵字 添加到成員方法上,線程拿走的也是this對(duì)象鎖public synchronized void withDraw(double money) {/*需要把同步的代碼,放到同步的語句塊中thread線程執(zhí)行到此處,遇到了synchronized 關(guān)鍵字,就會(huì)去找this的對(duì)象鎖 如果找到了this的對(duì)象鎖,則進(jìn)入同步語句塊 執(zhí)行程序當(dāng)同步語句塊代碼執(zhí)行結(jié)束的時(shí)候,thread線程歸還this的對(duì)象鎖在thread線程執(zhí)行同步語句塊的過程中,如果thread2線程也執(zhí)行以下代碼。遇到synchronized 關(guān)鍵字,所以去找this對(duì)象鎖,但是該對(duì)象被thread線程持有, 只能等待thread線程使用完以后再解鎖this對(duì)象鎖*///同步鎖 // synchronized (this) {//對(duì)賬戶進(jìn)行取款操作double after = balance - money;//延遲操作try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();//InterruptedException 線程中斷下拋出的異常 }//更新賬戶余額,重新賦值this.setBalance(after); // }}?
三、守護(hù)線程
①定義一個(gè)用戶線程
package com.steven.demo;//定義一個(gè)用戶線程 public class UserThread01 {public static void main(String[] args) {Runnable runnable = new UserTest();Thread thread = new Thread(runnable, "UserThread");thread.start();for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + "==== " + i);}System.out.println("主線程結(jié)束---");} }class UserTest implements Runnable {public void run() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + "==== " + i);}} }?
②改為守護(hù)線程
package com.steven.demo; //守護(hù)線程 //其他所有的用戶線程結(jié)束,則守護(hù)線程退出 //守護(hù)線程一般都是無限執(zhí)行的 守護(hù)線程最后結(jié)束(先執(zhí)行用戶線程) //設(shè)置守護(hù)線程以后,當(dāng)前主線程結(jié)束后,守護(hù)線程并沒有把所有的數(shù)據(jù)輸出就結(jié)束 也就是說 守護(hù)線程是為用戶線程服務(wù)的,當(dāng)用戶線程全部結(jié)束,守護(hù)線程會(huì)自動(dòng)化結(jié)束public class UserThread02 {public static void main(String[] args) {Thread thread = new UserTest02();thread.setName("thread");//將thread這個(gè)用戶線程 修改為守護(hù)線程thread.setDaemon(true);thread.start();//主線程 for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + "==== " + i);try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch block e.printStackTrace();}}System.out.println("主線程結(jié)束---");} } class UserTest02 extends Thread {public void run() {int i = 0;while (true) {i ++;System.out.println(Thread.currentThread().getName() +"====:"+i);try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}} }四、定時(shí)器簡單使用:
?
package com.steven.demo;import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Timer; import java.util.TimerTask;/*Timer 定時(shí)器*/ public class TimerTest01 {public static void main(String[] args) {System.out.println("來了"); Timer timer = new Timer();try {Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2018-10-07 19:26:02");//安排在指定的時(shí)間執(zhí)行指定的任務(wù)timer.schedule(new MyTimer(), date,1000*60*60*24);//date執(zhí)行后續(xù)任務(wù)的時(shí)間間隔 設(shè)置定時(shí)任務(wù):在2018-10-07 19:26:02執(zhí)行此任務(wù), 24小時(shí)執(zhí)行一次//timer.schedule(new MyTimer(), date,1000*2);//如果設(shè)置每天執(zhí)行一次:Date date = new SimpleDateFormat("HH:mm:ss").parse("19:26:02"); }catch (ParseException e) {e.printStackTrace();} catch (NullPointerException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalStateException e) {e.printStackTrace();}} }class MyTimer extends TimerTask {public void run() {System.out.println("=="+new Date());//==Sun Oct 07 19:26:02 CST 2018 }}?
?
?
?
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/StevenHuSir/p/Java_Thread.html
總結(jié)
以上是生活随笔為你收集整理的java-多线程操作全(Thread)-Timer简单使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 抓包分析数据(Charles以及Http
- 下一篇: MATLAB代码:基于分布式优化的多产消