多线程¶
1. Thread¶
- 耦合度低,调用start()方法去让线程进入等待状态,有JVM去调度该线程里面的执行体(run), 可以高效的并发执行,不要直接去调用run()方法。
eg:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class TestThread extends Thread { TestThread(String name) { super(name); } @Override public void run() { for (int i = 0; i < 30; i++) { System.out.println(getName() + " " + i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } } |
2. Runnable¶
便于共享
3. Join¶
当某个程序执行流中调用其他线程的join方法时,调用线程将会被阻塞,直到被join方法加入的join线程完成为止。
注
joinThread2.join(10000);调用线程等待join线程10s后,继续往下面执行,无需等待join线程执行结束,才继续执行。
eg:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public class RunThread { public static void main(String[] args) { JoinThread joinThread = new JoinThread("新线程"); joinThread.start(); for (int i = 0; i < 50; i++) { if (i == 20) { JoinThread joinThread2 = new JoinThread("新加入的线程"); joinThread2.start(); try { joinThread2.join(); // joinThread2.join(10000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + " " + i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class JoinThread extends Thread { JoinThread(String name) { super(name); } @Override public void run() { for (int i = 0; i < 30; i++) { System.out.println(getName() + " " + i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } |
4. 守护线程(Deamon Thread)¶
- 在后台运行,为其他线程提供服务。 JVM的垃圾回收器就是典型的守护线程。如果所有前台线程已死亡,那么守护线程也死亡。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public class RunThread { public static void main(String[] args) { DeamonThread deamonThread = new DeamonThread("守护线程"); deamonThread.setDaemon(true); // 一定要在start()之前设置 deamonThread.start(); for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + " " + i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class DeamonThread extends Thread { DeamonThread(String name) { super(name); } @Override public void run() { for (int i = 0; i < 30; i++) { System.out.println(getName() + " " + i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } |
5. 线程睡眠 sleep¶
- 让当前正在执行的线程暂停一段时间,进入阻塞状态。
6.线程同步(银行取钱例子)¶
1 2 3 4 5 6 7 | public class RunThread { public static void main(String[] args) { Account account = new Account("123", 1000); new DrawThread(account, 800).start(); new DrawThread(account, 800).start(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | class Account { private String accountNo; private int balance; public Account(String accountNo, int balance) { super(); this.accountNo = accountNo; this.balance = balance; } public String getAccountNo() { return accountNo; } public void setAccountNo(String accountNo) { this.accountNo = accountNo; } public int getBalance() { return balance; } public void setBalance(int balance) { this.balance = balance; } public int hashCode() { return accountNo.hashCode(); } public boolean equal(Object obj) { if (obj != null && obj.getClass() == Account.class) { Account account = (Account) obj; return account.getAccountNo().equals(accountNo); } return false; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class DrawThread extends Thread { private Account account; private int drawAmount; DrawThread(Account account, int drawAmount) { this.account = account; this.drawAmount = drawAmount; } @Override public void run() { if (drawAmount <= account.getBalance()) { System.out.println(getName() + " 成功取钱!吐钱: " + drawAmount); account.setBalance(account.getBalance() - drawAmount); System.out.println("账户余额: " + account.getBalance()); } else { System.out.println(getName() + " 取钱失败,账户余额不足! "); } } } |
7. 同步块¶
1 2 | synchronized (obj) { } |
8. 同步锁(Lock)¶
- ReadWriteLock(读写锁)
- ReentrantLock(可重入锁) -> 线程安全 (String和StringBuffer类比),使用Lock对象来进行同步时,锁定和释放出现在不同的作用范围时,通常建议使用finally来确保在必要时释放锁。
- ReetrantLock锁具有重入性,也就是说一段被锁保护的代码可以调用另一个被相同锁保护的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class X { private ReentrantLock lock = new ReentrantLock(); . . . public void method() { lock.lock(); try { . . . } finally { lock.unlock(); } } } |
上述 同步块 和 同步锁都符合”加锁 -> 访问 -> 释放锁”的操作模式。
9. 死锁¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | class LockA implements Runnable { Object lockA; Object lockB; LockA(Object lockA, Object lockB) { this.lockA = lockA; this.lockB = lockB; } @Override public void run() { synchronized (lockA) { System.out.println("获得LockA"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("等待获取LockB"); synchronized (lockB) { System.out.println("在LockA内部 去竞争LockB"); } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | class LockB implements Runnable { Object lockA; Object lockB; LockB(Object lockA, Object lockB) { this.lockA = lockA; this.lockB = lockB; } @Override public void run() { synchronized (lockB) { System.out.println("获得LockB"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("等待获取LockA"); synchronized (lockA) { System.out.println("在LockB内部 去竞争LockA"); } } } } |
10. 线程协调运行(wait, notify, notifyAll)(生产者和消费者模型)¶
1 2 3 4 5 6 7 8 | public class RunThread { public static void main(String[] args) { List<String> apples = new ArrayList<>(); Object obj = new Object(); new Thread(new Creator(apples, obj)).start(); new Thread(new Customer(apples, obj)).start(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | // 1.生产者 class Creator implements Runnable { private List<String> apples; private Object obj; Creator(List<String> apples, Object obj) { this.apples = apples; this.obj = obj; } @Override public void run() { while (true) { synchronized (obj) { if (0 < apples.size()) { try { obj.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } obj.notify(); for (int i = 1; i <= 5; i++) { String apple = "生产者生产的第 " + i + " 个苹果"; apples.add(apple); System.out.println(apple); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | // 2.消费者 class Customer implements Runnable { private List<String> apples; private Object obj; Customer(List<String> apples, Object obj) { this.apples = apples; this.obj = obj; } @Override public void run() { while (true) { synchronized (obj) { if (apples.size() == 0) { try { obj.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } obj.notify(); for (String apple : apples) { System.out.println("取走 " + apple); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } apples.clear(); } } } } |
11. Callable和FutureTask¶
Callable的功能比Runnable强大,可以有返回值和异常信息处理。通常情况下,Thread里面的target是要用run方法作为运行实体,FutureTask实现了Runnable接口,可以将Callable封装到FutureTask里面,作为与Thread交互的对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | public class RunThread { public static void main(String[] args) throws IOException { CallableThread callableThread = new CallableThread(); FutureTask<Integer> task = new FutureTask<Integer>(callableThread); for (int i = 0; i < 100; i++) { System.out.println("主线程名:" + Thread.currentThread().getName() + ", i = " + i); try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } if (i == 20) { new Thread(task, "返回值线程").start(); } } try { System.out.println("获取子线程的返回值" + task.get()); } catch (Exception e) { } } } class CallableThread implements Callable<Integer> { @Override public Integer call() throws Exception { int i; for (i = 0; i < 100; i++) { System.out.println("子线程名:" + Thread.currentThread().getName() + ", i = " + i); Thread.sleep(300); } return i; } } |