關(guān)鍵字
static
靜態(tài)內(nèi)部類與非靜態(tài)內(nèi)部類之間存在一個最大的區(qū)別:
非靜態(tài)內(nèi)部類在編譯完成之后會隱含地保存著一個引用,該引用是指向創(chuàng)建它的外圍內(nèi),但是靜態(tài)內(nèi)部類卻沒有。沒有這個引用就意味著:
1.它的創(chuàng)建是不需要依賴外圍類的創(chuàng)建。
2.它不能使用任何外圍類的非static成員變量和方法。
匿名內(nèi)部類和其他.
1.內(nèi)部類概述和訪問特點
A:內(nèi)部類概述:
把類定義在其他類的內(nèi)部,這個類就被稱為內(nèi)部類。
舉例:在類A中定義了一個類B,類B就是內(nèi)部類。
B:內(nèi)部類訪問特點
a:內(nèi)部類可以直接訪問外部類的成員,包括私有。
b:外部類要訪問內(nèi)部類的成員,必須創(chuàng)建對象。
多線程
創(chuàng)建方式
public class ThreadDemo {
public static void main(String[] args) {
// 創(chuàng)建對象
MyThread t1 = new MyThread() ;
MyThread t2 = new MyThread() ;
// 啟動線程: 需要使用start方法啟動線程, 如果我們在這里調(diào)用的是run方法,那么我們只是把該方法作為普通方法進行執(zhí)行
// t1.run() ;
// t1.run() ;
t1.start() ; // 告訴jvm開啟一個線程調(diào)用run方法
// t1.start() ; // 一個線程只能被啟動一次
t2.start() ;
}
}
public class MyThread extends Thread {
@Override
public void run() {
for(int x = 0 ; x < 1000 ; x++) {
System.out.println(x);
}
}
}
public static void main(String[] args) {
// 創(chuàng)建定義的類的對象
MyThread mt = new MyThread() ;
// 創(chuàng)建Thread的對象吧第三步創(chuàng)建的對象作為參數(shù)傳遞進來
Thread t1 = new Thread(mt , "張三") ;
Thread t2 = new Thread(mt , "李四") ;
// 啟動線程
t1.start() ;
t2.start() ;
}
public class MyThread implements Runnable {
@Override
public void run() {
for(int x = 0 ; x < 1000 ; x++) {
System.out.println(Thread.currentThread().getName() + "---" + x);
}
}
}
細節(jié)
1.run()和start()方法的區(qū)別
啟動線程: 需要使用start方法啟動線程, 如果我們在這里調(diào)用的是run方法,那么我們只是把該方法作為普通方法進行執(zhí)行。
2.一個線程只能被啟動一次
匿名內(nèi)部類方式
new Thread(){代碼…}.start();
new Thread(new Runnable(){代碼…}).start();
線程調(diào)度
線程有兩種調(diào)度模型
- 分時調(diào)度模型
所有線程輪流使用CPU的使用權(quán),平均分配每個線程占用 CPU 的時間片 - 搶占式調(diào)度模型
優(yōu)先讓優(yōu)先級高的線程使用 CPU,如果線程的優(yōu)先級相同,那么會隨機選擇一個,優(yōu)先級高的線程獲取的 CPU 時間片相對多一些。Java使用的是搶占式調(diào)度模型
線程控制

- 線程控制之休眠線程
- public static void sleep(long time) ;
time表達的意思是休眠的時間 , 單位是毫秒
- 線程控制之加入線程
- public final void join()
等待該線程執(zhí)行完畢了以后,其他線程才能再次執(zhí)行
注意事項: 在線程啟動之后,在調(diào)用方法
- 線程控制之禮讓線程
- public static void yield():
暫停當前正在執(zhí)行的線程對象,并執(zhí)行其他線程。
線程禮讓的原理是: 暫定當前的線程,然CPU去執(zhí)行其他的線程, 這個暫定的時間是相當短暫的; 當我某一個線程暫定完畢以后,其他的線程還沒有搶占到cpu的執(zhí)行權(quán) ; 那么這個是時候當前的線程會和其他的線程再次搶占cpu的執(zhí)行權(quán);
- 線程控制之守護線程
- public final void setDaemon(boolean on)
將該線程標記為守護線程或用戶線程。當正在運行的線程都是守護線程時,Java 虛擬機退出。 該方法必須在啟動線程前調(diào)用。
jvm會線程程序中存在的線程類型,如果線程全部是守護線程,那么jvm就停止。
- 線程控制之中斷線程
- public final void stop():
停止線程的運行
public void interrupt():
中斷線程(這個翻譯不太好),查看API可得當線程調(diào)用wait(),sleep(long time)方法的時候處于阻塞狀態(tài),可以通過這個方法清除阻塞
- wait()和sleep()的區(qū)別
sleep來自Thread類,和wait來自O(shè)bject類
調(diào)用sleep()方法的過程中,線程不會釋放對象鎖。而 調(diào)用 wait 方法線程會釋放對象鎖
sleep睡眠后不會讓系統(tǒng)資源,wait讓出系統(tǒng)資源其他線程可以占用CPU
sleep(milliseconds)需要指定一個睡眠時間,時間一到會自動喚醒
同步互斥鎖
synchronized的使用
synchronized代碼塊,被修飾的代碼成為同步語句塊,其作用的范圍是調(diào)用這個代碼塊的對象,我們在用synchronized關(guān)鍵字的時候,能縮小代碼段的范圍就盡量縮小,能在代碼段上加同步就不要再整個方法上加同步。這叫減小鎖的粒度,使代碼更大程度的并發(fā)。
synchronized方法,被修飾的方法成為同步方法,其作用范圍是整個方法,作用對象是調(diào)用這個方法的對象。
synchronized靜態(tài)方法,修飾一個static靜態(tài)方法,其作用范圍是整個靜態(tài)方法,作用對象是這個類的所有對象。
synchronized類,其作用范圍是Synchronized后面括號括起來的部分synchronized(className.class),作用的對象是這個類的所有對象。
synchronized(),()中是鎖住的對象, synchronized(this)鎖住的只是對象本身,同一個類的不同對象調(diào)用的synchronized方法并不會被鎖住,而synchronized(className.class)實現(xiàn)了全局鎖的功能,所有這個類的對象調(diào)用這個方法都受到鎖的影響,此外()中還可以添加一個具體的對象,實現(xiàn)給具體對象加鎖。
注意的點
- 當兩個并發(fā)線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內(nèi)只能有一個線程得到執(zhí)行。另一個線程必須等待當前線程執(zhí)行完這個代碼塊以后才能執(zhí)行該代碼塊。
public class Thread1 implements Runnable {
public void run() {
synchronized(this) {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " synchronized loop " + i);
}
}
}
public static void main(String[] args) {
Thread1 t1 = new Thread1();
Thread ta = new Thread(t1, "A");
Thread tb = new Thread(t1, "B");
ta.start();
tb.start();
}
}
//輸出
A synchronized loop 0
A synchronized loop 1
A synchronized loop 2
A synchronized loop 3
A synchronized loop 4
B synchronized loop 0
B synchronized loop 1
B synchronized loop 2
B synchronized loop 3
B synchronized loop 4
- 當一個線程訪問object的一個synchronized(this)同步代碼塊時,另一個線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。(兩個線程使用的是同一個對象)
public class Thread2 {
public void m4t1() {
synchronized(this) {
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
}
}
public void m4t2() {
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
}
public static void main(String[] args) {
final Thread2 myt2 = new Thread2();
Thread t1 = new Thread( new Runnable() { public void run() { myt2.m4t1(); } }, "t1" );
Thread t2 = new Thread( new Runnable() { public void run() { myt2.m4t2(); } }, "t2" );
t1.start();
t2.start();
}
}
//輸出
t1 : 4
t2 : 4
t1 : 3
t2 : 3
t1 : 2
t2 : 2
t1 : 1
t2 : 1
t1 : 0
t2 : 0
- 當一個線程訪問object的一個synchronized(this)同步代碼塊時,其他線程對object中所有其它synchronized(this)同步代碼塊的訪問將被阻塞(同上,兩個線程使用的是同一個對象)。
//修改Thread2.m4t2()方法:
public void m4t2() {
synchronized(this) {
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
}
}
//此種寫法也一樣
//修改Thread2.m4t2()方法如下:
public synchronized void m4t2() {
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
}
//輸出
t1 : 4
t1 : 3
t1 : 2
t1 : 1
t1 : 0
t2 : 4
t2 : 3
t2 : 2
t2 : 1
t2 : 0
- 類鎖與對象鎖不互斥
public class Test {
public static void main(String[] args) {
final InsertData insertData = new InsertData();
new Thread(){
@Override
public void run() {
insertData.insert();
}
}.start();
new Thread(){
@Override
public void run() {
insertData.insert1();
}
}.start();
}
}
class InsertData {
public synchronized void insert(){
System.out.println("執(zhí)行insert");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("執(zhí)行insert完畢");
}
public synchronized static void insert1() {
System.out.println("執(zhí)行insert1");
System.out.println("執(zhí)行insert1完畢");
}
}