多线程

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;
    }
}