java多线程和锁

方法1: 继承Thread

 1public class Main {
 2    public static void main(String[] args) throws InterruptedException {
 3        Worker worker1 = new Worker();
 4        worker1.setName("thread-worker1");
 5        Worker worker2 = new Worker();
 6        worker2.setName("thread_worker2");
 7        worker1.start();
 8        worker2.start();
 9        Thread.sleep(1000);
10        System.out.println("Main-thread finished!");
11    }
12}
13
14class Worker extends Thread {
15    @Override
16    public void run() {
17        for (int i = 0; i < 10; i++) {
18            System.out.println("Hello " + getName());
19            try {
20                Thread.sleep(1000);
21            } catch (InterruptedException e) {
22                throw new RuntimeException(e);
23            }
24        }
25    }
26}

方法2: 实现Runnable接口

 1public class Main {
 2    public static void main(String[] args) {
 3        Worker worker = new Worker("thread1");
 4        new Thread(worker).start();
 5        new Thread(worker).start();
 6    }
 7}
 8
 9class Worker implements Runnable{
10    private String name;
11
12   public Worker(String name) {
13       this.name = name;
14   }
15
16
17    @Override
18    public void run() {
19        for (int i = 0; i < 10; i++) {
20            System.out.println("Hello " + this.name);
21            try {
22                Thread.sleep(1000);
23            } catch (InterruptedException e) {
24                throw new RuntimeException(e);
25            }
26        }
27    }
28}

join(long millis): 等待该线程执行结束,父线程才会继续执行; 可以传入一个最长等待时间,超过该时间后继续执行父线程

例如:主线程要等worker1worker2进程结束后执行

 1package cc.bnblogs;
 2
 3public class Main {
 4    public static void main(String[] args) throws InterruptedException {
 5        Worker worker1 = new Worker();
 6        worker1.setName("thread-worker1");
 7        Worker worker2 = new Worker();
 8        worker2.setName("thread_worker2");
 9        worker1.start();
10        worker2.start();
11
12        worker1.join(); // 只有worker1执行完成之后才会执行后面的代码
13        worker2.join(); // 只有worker2执行完成之后才会执行后面的代码
14        System.out.println("Main-thread finished!");
15    }
16}
17
18class Worker extends Thread {
19    @Override
20    public void run() {
21        for (int i = 0; i < 10; i++) {
22            System.out.println("Hello " + getName());
23            try {
24                Thread.sleep(1000);
25            } catch (InterruptedException e) {
26                throw new RuntimeException(e);
27            }
28        }
29    }
30}

interrupt():从休眠中中断线程

 1public class Main {
 2    public static void main(String[] args) throws InterruptedException {
 3        Worker worker1 = new Worker();
 4        worker1.setName("thread-worker1");
 5        Worker worker2 = new Worker();
 6        worker2.setName("thread_worker2");
 7        worker1.start();
 8        worker2.start();
 9
10        // 主线程最多等待worker1线程5000ms
11        worker1.join(5000);
12        worker1.interrupt();  // 抛出InterruptedException异常
13
14        System.out.println("Main-thread finished!");
15    }
16}
17
18class Worker extends Thread {
19    @Override
20    public void run() {
21        for (int i = 0; i < 10; i++) {
22            System.out.println("Hello " + getName());
23            try {
24                Thread.sleep(1000);
25            } catch (InterruptedException e) {
26                // 收到InterruptedException后,结束该线程
27                System.out.println(getName() + " stop!");
28                break;
29            }
30        }
31    }
32}

setDaemon():设置某线程为守护线程

 1public class Main {
 2    public static void main(String[] args) throws InterruptedException {
 3        Worker worker1 = new Worker();
 4        worker1.setName("thread-worker1");
 5        Worker worker2 = new Worker();
 6        worker2.setName("thread_worker2");
 7        // 将worker1和worker2设置为守护线程
 8        // 除守护线程之外的其他线程结束后(这里只有主线程),守护线程会自动结束
 9        worker1.setDaemon(true);
10        worker2.setDaemon(true);
11
12        worker1.start();
13        worker2.start();
14
15        // 主线程休眠5s
16        Thread.sleep(5000);
17
18        System.out.println("Main-thread finished!");
19    }
20}
21
22class Worker extends Thread {
23    @Override
24    public void run() {
25        for (int i = 0; i < 10; i++) {
26            System.out.println("Hello " + getName());
27            try {
28                Thread.sleep(1000);
29            } catch (InterruptedException e) {
30                throw new RuntimeException();
31            }
32        }
33    }
34}

lock:获取锁,如果锁已经被其他线程获取,则阻塞 unlock:释放锁,并唤醒被该锁阻塞的其他线程

防止读写冲突,同一时间只有一个线程可以拥有锁,并进行写操作

 1import java.util.concurrent.locks.ReentrantLock;
 2
 3public class Main {
 4    public static void main(String[] args) throws InterruptedException {
 5        Worker worker1 = new Worker();
 6        worker1.setName("thread-worker1");
 7        Worker worker2 = new Worker();
 8        worker2.setName("thread_worker2");
 9
10        worker1.start();
11        worker2.start();
12
13        worker1.join();
14        worker2.join();
15
16        System.out.println("Main-thread finished!");
17        System.out.println("cnt: " + Worker.cnt);
18    }
19}
20
21class Worker extends Thread {
22    private static final ReentrantLock lock = new ReentrantLock();
23    public static int cnt = 0;
24
25    @Override
26    public void run() {
27        for (int i = 0; i < 200000; i++) {
28            lock.lock();
29            try {
30                cnt++;
31            }finally {
32                lock.unlock();
33            }
34        }
35    }
36}

java实现锁的语法糖,继承Thread类和实现Runnable接口的线程使用方式有点区别

还是上面的cnt++的例子

1.继承Thread

 1public class Main {
 2    public static void main(String[] args) throws InterruptedException {
 3        Worker worker1 = new Worker();
 4        worker1.setName("thread-worker1");
 5        Worker worker2 = new Worker();
 6        worker2.setName("thread_worker2");
 7
 8        worker1.start();
 9        worker2.start();
10
11        worker1.join();
12        worker2.join();
13
14        System.out.println("Main-thread finished!");
15        System.out.println("cnt: " + Worker.cnt);
16    }
17}
18
19class Worker extends Thread {
20    public static int cnt = 0;
21    private static final Object object = new Object();
22
23    @Override
24    public void run() {
25		//锁加到了object对象上,多个线程共享一个object
26        synchronized (object) {
27            for (int i = 0; i < 200000; i++) {
28                cnt++;
29            }
30        }
31    }
32}

2.实现Runnable接口

 1public class Main {
 2    public static void main(String[] args) throws InterruptedException {
 3        Worker worker = new Worker();
 4
 5        Thread worker1 = new Thread(worker);
 6        Thread worker2 = new Thread(worker);
 7
 8        worker1.start();
 9        worker2.start();
10
11        worker1.join();
12        worker2.join();
13
14        System.out.println("Main-thread finished!");
15        System.out.println("cnt: " + Worker.cnt);
16    }
17}
18
19class Worker implements Runnable {
20    public static int cnt = 0;
21
22    @Override
23    public void run() {
24        //锁加到了this对象上,而两个线程是由同一个worker创建而来的
25        synchronized (this) {
26            for (int i = 0; i < 200000; i++) {
27                cnt++;
28            }
29        }
30    }
31}

也可以直接将synchronized作用到方法上,和上面的代码等价

 1public class Main {
 2    public static void main(String[] args) throws InterruptedException {
 3        Worker worker = new Worker();
 4
 5        Thread worker1 = new Thread(worker);
 6        Thread worker2 = new Thread(worker);
 7
 8        worker1.start();
 9        worker2.start();
10
11        worker1.join();
12        worker2.join();
13
14        System.out.println("Main-thread finished!");
15        System.out.println("cnt: " + Worker.cnt);
16    }
17}
18
19class Worker implements Runnable {
20    public static int cnt = 0;
21
22    @Override
23    public void run() {
24        Worker.work();
25    }
26
27    private synchronized static void work() {
28        for (int i = 0; i < 200000; i++) {
29            cnt++;
30        }
31    }
32}

前面5个线程会等待1s后自动唤醒一个线程,唤醒的线程睡眠1s后叫醒下一个线程

 1public class Main {
 2    public static void main(String[] args) throws InterruptedException {
 3        for (int i = 0; i < 5; i++) {
 4            Worker worker = new Worker(true);
 5            worker.setName("Thread_" + i);
 6            worker.start();
 7        }
 8        Worker worker = new Worker(false);
 9        worker.setName("Thread_5");
10		// 第6个线程先睡2s再去唤醒线程,这时候已经晚了
11        Thread.sleep(2000);
12        worker.start();
13
14    }
15}
16
17class Worker extends Thread {
18    private final boolean needWait;
19    // 定义一个全局object
20    private static final Object object = new Object();
21
22    public Worker(boolean needWait) {
23        this.needWait = needWait;
24    }
25
26    @Override
27    public void run() {
28        synchronized (object) {
29            try {
30                if (needWait) {
31                    // 最多等待1s,超过1s会自动唤醒一个线程
32                    object.wait(1000);
33                    System.out.println(getName() + " 被唤醒了!");
34                    //睡眠1s后继续唤醒其他线程
35                    Thread.sleep(1000);
36                } else {
37                    // 不需要睡眠的线程唤醒一个线程
38                    object.notify();
39                    System.out.println("尝试唤醒其他线程");
40
41                }
42            } catch (InterruptedException e) {
43                throw new RuntimeException(e);
44            }
45        }
46    }
47}

当然也可以不使用静态变量object

 1public class Main {
 2    public static void main(String[] args) throws InterruptedException {
 3        Object object = new Object();
 4        for (int i = 0; i < 5; i++) {
 5            Worker worker = new Worker(object, true);
 6            worker.setName("Thread_" + i);
 7            worker.start();
 8        }
 9        Worker worker = new Worker(object, false);
10        worker.setName("Thread_5");
11        // 第6个线程先睡2s再去唤醒线程,这时候已经晚了
12        Thread.sleep(2000);
13        worker.start();
14
15    }
16}
17
18class Worker extends Thread {
19    private final boolean needWait;
20    private final Object object;
21
22    public Worker(Object object, boolean needWait) {
23        this.object = object;
24        this.needWait = needWait;
25    }
26
27    @Override
28    public void run() {
29        synchronized (object) {
30            try {
31                if (needWait) {
32                    // 最多等待1s,超过1s会自动唤醒一个线程
33                    object.wait(1000);
34                    System.out.println(getName() + " 被唤醒了!");
35                    //睡眠1s后继续唤醒其他线程
36                    Thread.sleep(1000);
37                } else {
38                    // 不需要睡眠的线程唤醒一个线程
39                    object.notify();
40                    System.out.println("尝试唤醒其他线程");
41
42                }
43            } catch (InterruptedException e) {
44                throw new RuntimeException(e);
45            }
46        }
47    }
48}