实现多线程的三种方式
(1)继承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
| package com.cskaoyan;
public class Demo {
public static void main(String[] args) {
for (int i = 0; i < 2; i++) { new MyThread().start(); }
} }
class MyThread extends Thread { @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(getName() + "打印了" + i); } } }
|
(2)实现Runnable接口
示例代码如下
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
| package com.cskaoyan;
public class Demo {
public static void main(String[] args) {
MyThread mt = new MyThread(); for (int i = 0; i < 2; i++) { new Thread(mt).start(); }
} }
class MyThread implements Runnable { @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + "打印了" + i); } } }
|
(3)实现Callable接口,重写call方法。
示例代码如下
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
| package com.cskaoyan;
import javax.swing.*; import java.util.concurrent.Callable; import java.util.concurrent.FutureTask;
public class Demo { public static void main(String[] args) {
Thread t = new Thread(new FutureTask(new A())); t.start(); System.out.println("main线程...");
} }
class A implements Callable {
@Override public Object call() throws Exception { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + "->" + i); } return null; }
}
|
多线程环境下共享数据安全问题
确保数据安全的两种方式
一个java对象相当于一把锁
同步代码块
1 2 3
| synchronized (锁对象) { }
|
同步方法
1 2 3
| public synchronized void method() {
}
|
生产者与消费者模式
两个线程交替打印
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
| package com.cskaoyan;
public class Demo {
public static void main(String[] args) {
Signal s = new Signal(); new Thread(new A(s)).start(); new Thread(new B(s)).start();
} }
class Signal { boolean flag = true; }
class A implements Runnable {
Signal s;
@Override public void run() { printA(); }
public A(Signal s) { this.s = s; }
public void printA(){ while (true) { synchronized (s) { if(s.flag){ System.out.println("A"); s.flag = false; s.notify(); }else { try { s.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } }
class B implements Runnable {
Signal s;
@Override public void run() { printB(); }
public B(Signal s) { this.s = s; }
public void printB(){ while (true) { synchronized (s) { if(!s.flag){ System.out.println("B"); s.flag = true; s.notify(); }else { try { s.wait(); } 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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| package com.cskaoyan; import java.util.Random;
public class Demo { public static void main(String[] args) {
Lock lock = new Lock();
new Thread(new MyThread1(lock)).start(); new Thread(new MyThread2(lock)).start();
} }
class Lock { Object o1 = new Object(); Object o2 = new Object(); }
class MyThread1 implements Runnable {
Lock lock;
@Override public void run() { test(); }
public MyThread1(Lock lock) { this.lock = lock; }
public void test(){ while (true){ synchronized (lock.o1) { synchronized (lock.o2) { System.out.println(Thread.currentThread().getName() + "进厕所..."); } } } } }
class MyThread2 implements Runnable {
Lock lock;
@Override public void run() { test(); }
public MyThread2(Lock lock) { this.lock = lock; }
public void test(){ while (true){ synchronized (lock.o2) { synchronized (lock.o1) { System.out.println(Thread.currentThread().getName() + "进厕所..."); } } } } }
|
如何避免死锁?
1 2 3 4 5
| synchronized (lock.o1) { synchronized (lock.o2) { code... } }
|
确保每个线程加锁的顺序一致,新增一把锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| synchronized (lock.o3){ synchronized (lock.o2) { synchronized (lock.o1) { code... } } }
synchronized (lock.o3){ synchronized (lock.o1) { synchronized (lock.o2) { code... } } }
|
线程间通信
通过wait
以及notify
实现线程间通信
线程A打印100以内的所有奇数
线程B打印100以内的所有偶数
示例代码如下
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| public class Demo { public static void main(String[] args) { Signal s = new Signal(); new Thread(new A(s)).start(); new Thread(new B(s)).start();
} }
class Signal { boolean flag = true; int i = 1; }
class A implements Runnable {
Signal s;
public A(Signal s) { this.s = s; }
@Override public void run() { printOdd(); }
public void printOdd() { while (s.i <= 100) { synchronized (s) { if (s.flag) { System.out.println("奇数线程:" + s.i++); s.flag = false; s.notify(); } else { try { s.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } }
class B implements Runnable {
Signal s;
public B(Signal s) { this.s = s; }
@Override public void run() { printEven(); }
public void printEven() { while (s.i <= 100) { synchronized (s) { if (!s.flag) { System.out.println("偶数线程:" + s.i++); s.flag = true; s.notify(); } else { try { s.wait(); } 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
| public class Demo { public static void main(String[] args) {
Thread t = new Thread(new A()); t.start();
try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("main线程"); } }
class A implements Runnable { @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
|
线程池
(1)线程池newCachedThreadPool
动态线程池
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
| import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;
public class Demo { public static void main(String[] args) {
ExecutorService pool = Executors.newCachedThreadPool(); Thread t = new Thread(new A()); for (int i = 0; i < 30; i++) { pool.submit(t); } System.out.println("main线程"); pool.shutdown();
} }
class A implements Runnable { @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + "->" + i); } } }
|
(2)线程池newFixedThreadPool
数量固定的线程池
1 2
| ExecutorService pool = Executors.newFixedThreadPool(10);
|
(3)线程池newSingleThreadExecutor
1 2
| ExecutorService pool = Executors.newSingleThreadExecutor();
|
如果线程有返回值,那么如何做呢?
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
| package com.cskaoyan;
import java.util.concurrent.*;
public class Demo { public static void main(String[] args) {
FutureTask futureTask = new FutureTask(new A()); Thread t = new Thread(futureTask); t.start(); try { String res = ((String) futureTask.get()); System.out.println(res); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println("main线程");
} }
class A implements Callable {
@Override public Object call() throws Exception { System.out.println(Thread.currentThread().getName()); return "线程A"; }
}
|
示例代码如下
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 39 40 41 42
| package com.cskaoyan;
import java.util.concurrent.*;
public class Demo { public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(10); A task = new A(); Future future1 = pool.submit(task); Future future2 = pool.submit(task); pool.shutdown(); try { String res1 = ((String) future1.get()); String res2 = ((String) future2.get()); System.out.println(res1); System.out.println(res2); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println("main线程"); } }
class A implements Callable {
@Override public Object call() throws Exception { System.out.println(Thread.currentThread().getName()); return "分支线程..."; }
}
|
定时任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import java.util.Timer; import java.util.TimerTask;
public class Demo { public static void main(String[] args) {
Timer timer = new Timer(); timer.schedule(new MyTask(), 5000); System.out.println("main");
} }
class MyTask extends TimerTask { @Override public void run() { System.out.println("定时任务..."); } }
|