線程的狀態
線程的六種狀態
1.新建狀態(new 線程對象)
2.運行狀態(調用start方法)
3.受阻塞狀態(等待CPU的執行資源)
4.休眠狀態(調用了sleep(時間)方法)
5.等待狀態(調用了wait方法)
6.死亡狀態(run執行完畢)
匿名內部類
線程的第三種創建方式:
匿名內部類方式:相當於創建了一個該類的子類對象
new 父類或接口名(){
重寫父類方法
};
這裏new出來的就是這個類的子類對象
示例代碼:
class Test{
public void fun() {
System.out.println("我是父類的fun方法");
}
}
public static void fun1() {
Test test = new Test() {
@Override
public void fun() {
System.out.println("我是子類的fun方法");
}
};
test.fun();
}
接口:
interface TestInter{
public abstract void fun();
}
public static void fun2() {
new TestInter() {
@Override
public void fun() {
System.out.println("我是實現類的fun方法");
}
}.fun();
}
需求:利用匿名內部類方式給TreeSet集合中的學生對象按年齡排序
TreeSet<Student> set = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}
});
set.add(new Student("sc", 18));
set.add(new Student("kd", 19));
set.add(new Student("kb", 17));
for (Student student : set) {
System.out.println(student);
}
匿名內部類創建線程
繼承:
new Thread() {
@Override
public void run() {
System.out.println("-----");
}
}.start();
接口:
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("|||||");
}
};
new Thread(runnable).start();
合一起:
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("`````");
}
});
thread.start();
線程休眠
sleep()的作用是讓當前線程休眠,即當前線程會從運行狀態進入到休眠狀態。
sleep()會指定休眠時間
代碼示例:
public class Demo04 {
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 100; i++) {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + i);
}
}
}
class SleepThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 50; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + i);
}
}
}
同步鎖(同步代碼塊)
同步鎖:鎖可以是任意對象,要保證鎖的唯一
同步鎖規則:
線程遇到鎖可以進入同步代碼塊(並且攜帶鎖)
當線程執行代碼塊中的代碼後 把鎖返還
線程沒有遇到鎖 會在同步代碼塊外等待 遇到鎖才能進
賣火車票問題:
public class Demo {
public static void main(String[] args) {
Tickets t = new Tickets();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
Thread t3 = new Thread(t);
t1.start();
t2.start();
t3.start();
}
}
class Tickets implements Runnable{
private int tickets = 50;
private Object obj = new Object();
@Override
public void run() {
while (true) {
synchronized (obj) {
if (tickets > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "--" + tickets);
tickets--;
} else {
break;
}
}
Thread.yield();
}
}
}
在方法中添加synchronized關鍵詞 把方法變成 同步方法
class Tickets1 implements Runnable{
private int tickets = 50;
private Object obj = new Object();
@Override
public void run() {
while (true) {
if (sellTickets()) {
break;
}
Thread.yield();
}
}
public synchronized boolean sellTickets() {
if (tickets > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "--" + tickets);
tickets--;
return false;
} else {
return true;
}
}
}
死鎖
死鎖:在編寫多線程的時候,必須要注意資源的使用問題,如果兩個或多個線程分別擁有不同的資源,
而同時又需要對方釋放資源才能繼續運行時,就會發生死鎖。比如如果線程1持有鎖A並且想獲得鎖B,線程2持有鎖B並且想獲得鎖A,那麼這兩個線程將永遠等待下去,產生了死鎖
模擬線程死鎖:
public class Demo07 {
public static void main(String[] args) {
DieLock dl = new DieLock();
Thread t1 = new Thread(dl);
Thread t2 = new Thread(dl);
t1.start();
t2.start();
}
}
class LockA {
private LockA() {
}
public static final LockA LOCK_A = new LockA();
}
class LockB {
private LockB() {
}
public static final LockB LOCK_B = new LockB();
}
class DieLock implements Runnable{
private boolean isTrue = true;
@Override
public void run() {
while (true) {
if (isTrue) {
synchronized (LockA.LOCK_A) {
System.out.println("LOCK_A");
synchronized (LockB.LOCK_B) {
System.out.println("LOCK_B");
}
}
} else {
synchronized (LockB.LOCK_B) {
System.out.println("LOCK_B");
synchronized (LockA.LOCK_A) {
System.out.println("LOCK_A");
}
}
}
isTrue = !isTrue;
}
}
}
Lock接口
JDK1.5 鎖 Lock接口
使用Lock鎖
lock.lock();
try{
寫操作共享數據的代碼
} finally {
lock.unlock();
}
接口實現創建線程好處:
1.避免直接繼承Thread類的侷限性(避免單繼承)
2.接口即插即用 減少類與類之間的聯繫(可以解耦)
使用接口Lock接口鎖:
public class Demo {
public static void main(String[] args) {
Tickets3 tickets3 = new Tickets3();
Thread t1 = new Thread(tickets3);
Thread t2 = new Thread(tickets3);
Thread t3 = new Thread(tickets3);
t1.start();
t2.start();
t3.start();
}
}
class Tickets3 implements Runnable{
private int tickets = 50;
private ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
lock.lock();
try {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "--" + tickets);
tickets--;
} else {
break;
}
} finally {
lock.unlock();
}
Thread.yield();
}
}
}