線程和進程:操作系統執行多任務,每個任務就是進程;進程執行多任務,每個任務就是線程;包含關系 。
一、多線程創建和啟動:
1、繼承Thread:重寫run()方法,調用start()啟動線程。
public class ThreadDemo extends Thread{
@Override public void run() {
//具體方法
}
}
2、實現Runnable接口創建線程類,調用start()啟動線程。
public class RunnableDemo implements Runnable {
public void run() {
//具體方法
}
}
Thread類其實也實現了Runable接口。
二、線程資源共享。
ThreadDemo類
public class ThreadDemo extends Thread{
public Integer count = 10;
public String lock = "lock";
public ThreadDemo(String name) {
super(name);
}
@Override
public void run() {
synchronized (lock){
System.out.println(Thread.currentThread().getName() + " is running. count:"+count--);
}
}
}
資源不共享:
public class ThreadTest {
public static void main(String[] args) {
//資源不共享
for (int i = 1; i <= 10; i++) {
String name = "t"+i;
new ThreadDemo(name).start();
}
}
}
運行結果:
t4 is running. count:10
t10 is running. count:10
t6 is running. count:10
t1 is running. count:10
t5 is running. count:10
t2 is running. count:10
t8 is running. count:10
t9 is running. count:10
t3 is running. count:10
t7 is running. count:10
資源共享:
public class ThreadTest {
public static void main(String[] args) {
//資源共享
ThreadDemo t = new ThreadDemo("t1");
for (int i = 1; i <= 10; i++) {
new Thread(t).start();
}
}
運行結果:
Thread-0 is running. count:10
Thread-2 is running. count:9
Thread-1 is running. count:8
Thread-7 is running. count:7
Thread-6 is running. count:6
Thread-8 is running. count:5
Thread-3 is running. count:4
Thread-4 is running. count:3
Thread-5 is running. count:2
Thread-9 is running. count:1
三、線程方法
線程的生命周期
有新建(new),就緒(Runnable),運行(Running),阻塞(Blocked)和死亡(Dead)5種狀態.
3.1 join()和join(long millis),等待join的線程執行完了,被join的線程繼續執行。
public class ThreadTest {
public static void main(String[] args) {
try {
ThreadDemo thread1 = new ThreadDemo("thread1");
ThreadDemo thread2 = new ThreadDemo("thread2");
thread1.start();
// thread1.join();
System.out.println("main is running.");
thread2.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
運行結果:
main is running.
thread1 is running.
thread2 is running.
將注釋去掉:
運行結果
thread1 is running.
main is running.
thread2 is running.
調用Thread對象的setDaemon(true)方法可將指定線程設置成后台線程.
要將某個線程設置為后台線程,必須在start()之前調用
3.2 線程睡眠sleep(long millis)
sleep()方法比yield()方法有更好的可移植性,通常不建議使用yield()方法來控制並發線程的執行.
3.3 改變線程的優先級
Thread類提供了setPriority(int newPriority)和getPriority()來設置
和返回指定線程的優先級.10最大,1最小,正常為5。
3.4 線程同步
1.synchronized(obj){
}
2.synchronized修飾某個方法或代碼塊,但不能修飾構造器和成員變量。
Java語言的關鍵字,當它用來修飾一個方法或者一個代碼塊的時候,能夠保證在同一時刻最多只有一個線程執行該段代碼。
1、當兩個並發線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內只能有一個線程得到執行。另一個線程必須等待當前線程執行完這個代碼塊以后才能執行該代碼塊。
2、然而,當一個線程訪問object的一個synchronized(this)同步代碼塊時,另一個線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。
3、尤其關鍵的是,當一個線程訪問object的一個synchronized(this)同步代碼塊時,其他線程對object中所有其它synchronized(this)同步代碼塊的訪問將被阻塞。
4、第三個例子同樣適用其它同步代碼塊。也就是說,當一個線程訪問object的一個synchronized(this)同步代碼塊時,它就獲得了這個object的對象鎖。結果,其它線程對該object對象所有同步代碼部分的訪問都被暫時阻塞。
5、以上規則對其它對象鎖同樣適用.
延伸:單線程環境下應該使用StringBuilder來保證較好的性能,當需啊喲保證多線程安全時,
就 應該使用StringBuffer
四、同步鎖(Lock)
Lock是控制多個線程對共享資源進行訪問的工具.通常,鎖提供了對共享資源的獨占訪問,每次只能有一個
線程對Lock對象加鎖,線程開始訪問共享資源之前,應該先獲得Lock對象.
ReentrantLock鎖具有可重入性,也就是說,一個線程可以對已被加鎖的ReentrantLock鎖再次加鎖
ReentrantLock對象會維持一個計數器來追蹤lock()方法的嵌套調用,線程在每次調用lock()加鎖后,必須顯示調用unlock()來釋放鎖,所以一段被鎖包不戶的代碼可以調用另一個被相同鎖保護的方法.
public class ThreadDemo extends Thread{
public Integer count = 1;
private final ReentrantLock lock = new ReentrantLock();
public ThreadDemo(String name) {
super(name);
}
@Override
public void run() {
lock.lock();
try {
//執行操作
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
后續:
線程池,死鎖,生產者消費者模式,以及線程間通信不再介紹。
由於wait方法是在Object上的,而sleep方法是在Thread上,當用Thread.sleep時,並不能改變對象的狀態,因此也不會釋放鎖
多寫代碼多讀書,做個安靜的Coder。