線程基本概念java
進程:內存中正在進行的一個程序多線程
線程:進程中的一個執行流程併發
多線程:有兩個 或者 兩個以上併發的執行流程ide
線程的生命週期,線程分爲如下五種狀態this
(阻塞) 暫停執行spa
sleep:等待多少毫秒;超過了以後回覆就緒狀態等待cpu調用執行
join:等待其餘線程執行完,線程A調用了線程B的join();方法,那麼線程A等線程B執行完再執行線程
線程圖解:對象
主線程blog
當Java程序啓動時,一個線程馬上運行,該線程通 常叫作程序的主線程(main thread),==它是程序 開始時就執行的==。繼承
主方法就是主線程的任務 main();
public class TestThreadMain {
public static void main(String[] args) {
// 得到當前的線程 主線程名字,優先級,主線程組
System.out.println(Thread.currentThread());//Thread[main,5,main]
System.out.println(Thread.currentThread().getName());//main
}
}
問題:啓動一個java應用程序至少啓動幾個主線程?
會先啓動兩個線程:一個主線程,一個垃圾回收線程
子線程
默認的名字:Thread —— 數字
建立子線程
區別:
1. 繼承Thread類,繼承了Thread類的全部能夠繼承的;Runnable接口,只有run();
2. Runnable接口有利於資源共享
但願主線程最後結束
/** 建立子線程示例代碼 */
//建立子線程方法一:繼承自Thread類
class MyThread extends Thread{
MyThread(String name){
super(name);
}
//子線程的任務功能在run中
@Override
public void run() {
for(int i = 1; i<= 3 ; i++){
System.out.println(Thread.currentThread().getName() +":"+i);
}
}
}
//建立子線程方法二:實現Runnable 接口 用的較多,有利於資源共享
class ThreadDemo implements Runnable{
@Override
public void run() {
for(int i = 1; i<= 3 ; i++){
System.out.println(Thread.currentThread().getName() +"吃飯");
}
}
}
public class TestThread1 {
public static void main(String[] args) {
// //建立一個線程對象
// Thread t = new Thread();
// //啓動線程
// t.start();
// //建立一個子線程
// MyThread t1 = new MyThread("t1");//新建
// //啓動子線程,必須用start,而且只能啓動一次
// t1.start();//就緒
//不是線程對象
ThreadDemo demo = new ThreadDemo();
// 綁定ThreadDemo類對象
//Thread zhangsan = new Thread(demo);
Thread zhangsan = new Thread(demo,"張三");
Thread lisi = new Thread(demo,"李四");
//設置優先級
/* lisi.setPriority(10);
zhangsan.setPriority(1);*/
//最低,普通,最高 比直接賦予數字好一些
//1 5 10
zhangsan.setPriority(Thread.MAX_PRIORITY);
zhangsan.setPriority(Thread.MIN_PRIORITY);
zhangsan.setPriority(Thread.NORM_PRIORITY);
//啓動線程
zhangsan.start();
lisi.start();
//但願主線程最後結束方法一
/* try {
Thread.sleep(1000);//等1000毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}*/
////但願主線程最後結束方法二:判斷子線程是否運行
/* if(zhangsan.isAlive() || lisi.isAlive()){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}*/
//但願主線程最後結束方法三:讓子線程都執行完才能恢復主線程
try {
zhangsan.join();
lisi.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("主線程結束");
}
}
線程優先級
1 – 10
10最高
/** 建立子線程 */
//建立子線程方法一:繼承自Thread類
class MyThread extends Thread{
MyThread(String name){
super(name);
}
//子線程的任務功能在run中
@Override
public void run() {
for(int i = 1; i<= 3 ; i++){
System.out.println(Thread.currentThread().getName() +":"+i);
}
}
}
//建立子線程方法二:實現Runnable 接口 用的較多,有利於資源共享
class ThreadDemo implements Runnable{
@Override
public void run() {
for(int i = 1; i<= 3 ; i++){
System.out.println(Thread.currentThread().getName() +"吃飯");
}
}
}
public class TestThread1 {
public static void main(String[] args) {
// //建立一個線程對象
// Thread t = new Thread();
// //啓動線程
// t.start();
// //建立一個子線程
// MyThread t1 = new MyThread("t1");//新建
// //啓動子線程,必須用start,而且只能啓動一次
// t1.start();//就緒
//不是線程對象
ThreadDemo demo = new ThreadDemo();
// 綁定ThreadDemo類對象
//Thread zhangsan = new Thread(demo);
Thread zhangsan = new Thread(demo,"張三");
Thread lisi = new Thread(demo,"李四");
//設置優先級
/* lisi.setPriority(10);
zhangsan.setPriority(1);*/
//最低,普通,最高 比直接賦予數字好一些
//1 5 10
zhangsan.setPriority(Thread.MAX_PRIORITY);
zhangsan.setPriority(Thread.MIN_PRIORITY);
zhangsan.setPriority(Thread.NORM_PRIORITY);
//啓動線程
zhangsan.start();
lisi.start();
//但願主線程最後結束方法一
/* try {
Thread.sleep(1000);//等1000毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}*/
////但願主線程最後結束方法二:判斷子線程是否運行
/* if(zhangsan.isAlive() || lisi.isAlive()){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}*/
////但願主線程最後結束方法三:讓子線程都執行完才能恢復主線程
try {
zhangsan.join();
lisi.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("主線程結束");
}
}
線程其它方法interrupt()線程中斷 :sleep()和join()
**問題:**java線程何時會引起InterruptedException ?
前提:當前線程處於sleep或者join時,被其餘線程中斷了,那麼當前線程會進行異常處理
class ThreadDemo1 implements Runnable{
@Override
public void run() {
for(int i = 1 ; i <=5 ; i++){
System.out.println(Thread.currentThread().getName()+","+i);
if(i == 3){
try {
//Thread.sleep(1000);
Thread.currentThread().join();
} catch (InterruptedException e) {
System.out.println("進入異常處理了");
// e.printStackTrace();
}
}
}
}
}
public class TestThreadInterrupt {
public static void main(String[] args) {
ThreadDemo1 demo1 = new ThreadDemo1();
Thread t1 = new Thread(demo1);
t1.start();
//主線程調用了子線程t1的interrupt方法,子線程t1被中斷進入異常處理
t1.interrupt();
}
}
yield() 線程讓步 (瞭解便可,如今基本不用):
Thread.yield():不能徹底保證線程讓步
class ThreadDemo1 implements Runnable{
@Override
public void run() {
for(int i = 1 ; i <=5 ; i++){
System.out.println(Thread.currentThread().getName()+","+i);
if(i == 3){
try {
//Thread.sleep(1000);
Thread.currentThread().join();
} catch (InterruptedException e) {
System.out.println("進入異常處理了");
// e.printStackTrace();
}
}
}
}
}
public class TestThreadInterrupt {
public static void main(String[] args) {
ThreadDemo1 demo1 = new ThreadDemo1();
Thread t1 = new Thread(demo1);
t1.start();
//主線程調用了子線程t1的iterrupt方法,子線程t1被中斷進入異常處理
t1.interrupt();
}
}
線程的同步什麼是同步
某一時刻 此資源 只能被一個線程獨佔。
線程同步的真實意思和字面意思剛好相反。線程同步的真實意思,實際上是「排隊」:幾個線程之間要排隊,一個一個對共享資源進行操做,而不是同時進行操做。
爲何使用同步
當兩個或兩個以上的線程須要共享資源,他們須要某種方法來肯定資源在某一時刻僅被一個線程佔用,達到此目的的過程叫作同步。(某一時刻資源只能被一個線程獨佔)
使用同步
synchronized(對象){
同步塊;
}
同步方法,鎖的是對象 this
synchronized 方法{ }
1
/**同步示例代碼*/
class Bank implements Runnable{
int money = 0;
//存錢
//同步方法
synchronized public void setMoney(){
money += 100;//存100
System.out.println(Thread.currentThread().getName() + "存了100,餘額:" +money);
}
@Override
public void run() {
for(int i = 0 ; i < 3 ; i++){
//同步鎖
//同步塊
/* synchronized(this){
setMoney();
}*/
setMoney();
}
}
}
public class TestBank {
public static void main(String[] args) {
Bank bank = new Bank();
Thread zhangsan = new Thread(bank,"zhangsan");
Thread lisi = new Thread(bank,"lisi");
zhangsan.start();
lisi.start();
}
}
Lock優點
能夠顯示加鎖,釋放鎖
得到鎖:
當一個線程 訪問此對象的 同步塊 或 同步方法的時候,
申請同步鎖,申請成功了,就得到了鎖。在執行 同步塊
和 同步方法的過程當中,其它線程 進入 線程鎖定池中處於
阻塞狀態。只有 當前執行鎖的線程 釋放了鎖 其它線程
纔有 機會 得到CPU的調用執行。
釋放鎖:
1.同步方法或同步塊中的 代碼正常執行完了,就釋放了;
2. 出現了未處理的 異常Exception和
Error時 ,釋放鎖;
3。 break,return語句,會結束方法或
代碼塊,那麼會釋放鎖。
4. 執行了 wait()會釋放鎖。
語法:
try{
加鎖lock
}finally{
釋放unLock
}
lock做用
能夠顯示加鎖和釋放鎖
提供了更多功能
死鎖
每一個對象只有一個鎖(lock)不之相關聯
實現同步是要很大的系統開銷做爲代價的,甚至可 能形成死鎖,因此儘可能避免無謂的同步控制
/**死鎖示例代碼 */
class Zhangsan{
public void say(){
System.out.println("你給我書,我就給你畫");
}
public void get(){
System.out.println("張三得到了書");
}
}
class Lisi{
public void say(){
System.out.println("你給我畫,我就給你書");
}
public void get(){
System.out.println("李四得到了畫");
}
}
class LockDemo implements Runnable{
static Zhangsan zhangsan = new Zhangsan();
static Lisi lisi = new Lisi();
boolean tag ;
@Override
public void run() {
if(tag == true){//張三
synchronized(zhangsan){
zhangsan.say();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized(lisi){
zhangsan.get();
}
}
}else{//李四
synchronized(lisi){
lisi.say();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized(zhangsan){
lisi.get();
}
}
}
}
}
public class Testlock {
public static void main(String[] args) {
LockDemo demo1 = new LockDemo();
demo1.tag = true;
LockDemo demo2 = new LockDemo();
demo2.tag = false;
Thread t1 = new Thread(demo1);
Thread t2 = new Thread(demo2);
t1.start();
t2.start();
}
}
wait()和sleep的區別:
區別:
時間參數
wait()能夠可定時間也能夠丌指定; sleep()必須指定時間;
同步狀態
sleep()釋放執行權,不釋放鎖 ;wait釋放執行權,釋放鎖
class Show implements Runnable{
int i = 10 ;
@Override
synchronized public void run() {
for(; i >= 0 ; i--){
if(i == 5 && Thread.currentThread().getName().equals("t1:")){
try {
//Thread.sleep(100000);
wait(1000);
System.out.println("我醒了");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+i);
}
}
}
public class Exercise1 {
public static void main(String[] args) {
Show sh = new Show();
Thread t1 = new Thread(sh,"t1:");
Thread t2 = new Thread(sh,"t2:");
t1.start();
t2.start();
}
}
包子鋪實例理解wait()、notify()
package day26;
class QingFeng {
private int count;//包子數量
private boolean tag = false;//true ->有包子,false->沒包子
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
//生產包子
synchronized public void put(int count){
//有包子,休息
if(tag == true){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//沒有包子 false
this.count = count;
System.out.println("生產了" +this.count);
tag = true;
notify();//喚醒銷售
}
//銷售包子
synchronized public void get(){
//沒包子可賣,休息一會
if(tag == false){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 有包子true
System.out.println("賣了" +this.count);
tag = false;//賣完了
notify();//喚醒廚師
}
}
//生產
class Producer implements Runnable{
QingFeng qingfeng;
public Producer(QingFeng qingfeng) {
super();
this.qingfeng = qingfeng;
}
public Producer() {
super();
}
@Override
public void run() {
//生產
for(int i = 1 ; i <=5 ; i++){
qingfeng.put(i);
}
}
}
//銷售
class Consumer implements Runnable{
QingFeng qingfeng;
public Consumer() {
super();
}
public Consumer(QingFeng qingfeng) {
super();
this.qingfeng = qingfeng;
}
@Override
public void run() {
for(int i = 1 ; i <= 5 ; i++){
qingfeng.get();
}
}
}
public class Exercise2 {
public static void main(String[] args) {
QingFeng qingfeng = new QingFeng();
Producer pro = new Producer(qingfeng);
Consumer con = new Consumer(qingfeng) ;
Thread t1 = new Thread(pro);
Thread t2 = new Thread(con);
t1.start();
t2.start();
}
}