Java多线程基础
Java多线程1 线程创建1.1 继承Thread类1.2 实现Runnable接口1.3 实现Callable接口1.4 静态代理模式1.5 线程创建总结2 线程状态2.1 线程停止2.2 线程休眠2.3 线程礼让2.4 线程强制执行2.5 观测线程状态2.6 线程优先级2.7 守护线程3 线程同步3.1 线程同步机制3.2 并发问题3.3 同步方法与同步块3.4 JUC安全类型集合3.5 死锁3.6 Lock锁4 线程通信4.1 线程通信方法4.2 管程法4.3 信号灯法5 线程池5.1使用线程池
Java多线程
1 线程创建
1.1 继承Thread类
创建线程方式一:继承Thread类
- 继承Thread类,重写run方法,调用start开始线程
xxxxxxxxxx
201/*创建线程:继承Thread类,重写run方法,调用start开始线程*/
2public class TestThread extends Thread{
3
4 public void run() {
5 for (int i = 0; i < 20; i++) {
6 System.out.println("----线程执行----" + i);
7 }
8 }
9
10 public static void main(String[] args) {
11 /*创建线程对象*/
12 TestThread testThread = new TestThread();
13 /*调用start方法*/
14 testThread.start();
15
16 for (int i = 0; i < 20; i++) {
17 System.out.println("----主线程执行----" + i);
18 }
19 }
20}
1.2 实现Runnable接口
创建线程方式二:实现runnable接口
- 实现runnable接口,重写run方法,执行start,开启线程
xxxxxxxxxx
201/*实现runnable接口,重写run方法,执行start*/
2public class TestThread implements Runnable {
3
4
5 public void run() {
6 for (int i = 0; i < 20; i++) {
7 System.out.println("----线程执行----" + i);
8 }
9 }
10
11 public static void main(String[] args) {
12 /*创建Runnable接口的实现类对象*/
13 TestThread test = new TestThread();
14
15 /*创建线程对象*/
16 Thread thread = new Thread(test);
17
18 thread.start();
19 }
20}
1.3 实现Callable接口
创建线程方式三:实现Callable接口
- 实现Callable接口,重写call方法,创建执行服务,提交执行,获取结果,关闭服务
xxxxxxxxxx
271/*实现Callable接口
2* 1.可以定义返回值
3* 2.可以抛出异常
4*/
5public class TestCallable implements Callable<Boolean> {
6
7 public Boolean call() {
8 System.out.println(Thread.currentThread().getName()+"线程执行");
9 return true;
10 }
11
12 public static void main(String[] args) throws ExecutionException, InterruptedException {
13 TestCallable callable1 = new TestCallable();
14 TestCallable callable2 = new TestCallable();
15
16 /*创建执行服务*/
17 ExecutorService ser = Executors.newFixedThreadPool(2);
18 /*提交执行*/
19 Future<Boolean> result1 = ser.submit(callable1);
20 Future<Boolean> result2 = ser.submit(callable2);
21 /*获取结果*/
22 boolean rs1 = result1.get();
23 boolean rs2 = result2.get();
24 /*关闭服务*/
25 ser.shutdown();
26 }
27}
1.4 静态代理模式
- 代理对象和真实对象需要实现同一个接口,代理对象代理真实角色
- 代理对象可以做很多真实对象做不了的事 ,真实对象专注做自己的事情
xxxxxxxxxx
371/*接口*/
2interface Marry{
3 void HappyMarry();
4}
5
6/*真实角色*/
7class You implements Marry{
8
9 public void HappyMarry() {
10 System.out.println("Marry");
11 }
12}
13
14/*代理角色*/
15class WeddingCompany implements Marry{
16
17 private Marry target;
18
19 public WeddingCompany(Marry target){
20 this.target = target;
21 }
22
23
24 public void HappyMarry() {
25 before();
26 this.target.HappyMarry();
27 after();
28 }
29
30 private void after() {
31 System.out.println("结婚后,收尾款");
32 }
33
34 private void before() {
35 System.out.println("结婚前,布置现场");
36 }
37}
main:
xxxxxxxxxx
91public static void main(String[] args) {
2 new Thread(()-> System.out.println("thread")).start();
3
4 Marry you = new You();
5 WeddingCompany weddingCompany = new WeddingCompany(you);
6 weddingCompany.HappyMarry();
7 System.out.println("------------");
8 you.HappyMarry();
9}
1.5 线程创建总结
xxxxxxxxxx
421public class ThreadNew {
2 public static void main(String[] args) {
3 //继承Thread
4 new MyThread1().start();
5 //实现Runnable
6 new Thread(new MyThread2()).start();
7 //实现Callable
8 FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread3());
9 new Thread(futureTask).start();
10
11 try {
12 Integer integer = futureTask.get();
13 System.out.println(integer);
14 } catch (InterruptedException e) {
15 e.printStackTrace();
16 } catch (ExecutionException e) {
17 e.printStackTrace();
18 }
19 }
20}
21
22class MyThread1 extends Thread{
23
24 public void run() {
25 System.out.println("Thread1 -- extends Thread");
26 }
27}
28
29class MyThread2 implements Runnable{
30
31 public void run() {
32 System.out.println("Thread2 -- implements Runnable");
33 }
34}
35
36class MyThread3 implements Callable<Integer>{
37
38 public Integer call() throws Exception {
39 System.out.println("Thread3 -- implements Callable");
40 return 100;
41 }
42}
2 线程状态
新建状态:
使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。
就绪状态:
当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。
运行状态:
如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。
阻塞状态:
如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:
- 等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
- 同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
- 其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
死亡状态:
一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。
2.1 线程停止
线程停止:
- 线程最好是正常停止
- 需要停止线程设置一个标志位,通过设置标志位,改变标志位停止线程
xxxxxxxxxx
331/*测试停止
2* 1.建议正常停止
3* 2.建议使用标志位*/
4public class TestStop implements Runnable{
5 /*设置一个标志位*/
6 private boolean flag = true;
7
8
9 public void run() {
10 int i = 0;
11 while (flag){
12 System.out.println("run.......thread"+i++);
13 }
14 }
15
16 public void stop(){
17 this.flag = false;
18 }
19
20 public static void main(String[] args) {
21 TestStop testStop = new TestStop();
22
23 new Thread(testStop).start();
24
25 for (int i = 0; i < 1500; i++) {
26 System.out.println("main.......thread"+i);
27 if(i == 1000){
28 testStop.stop();
29 System.out.println("stop......thread");
30 }
31 }
32 }
33}
2.2 线程休眠
- sleep时间到达之后线程进入就绪状态
- 每个对象都有一个锁,sleep不会释放锁
xxxxxxxxxx
11Thread.sleep(200);
2.3 线程礼让
- 线程礼让,让当前执行的线程暂停,不阻塞
- 线程从运行状态变为就绪状态
- 礼让不一定成功,根据CPU调度执行
xxxxxxxxxx
11Thread.yield();
2.4 线程强制执行
- join,等待此线程执行完成才会执行其他线程,其他线程阻塞
xxxxxxxxxx
11thread.join();
2.5 观测线程状态
xxxxxxxxxx
11thread.getState();
xxxxxxxxxx
291public class TestState {
2
3 public static void main(String[] args) throws InterruptedException {
4 Thread thread = new Thread(()->{
5 for (int i = 0; i < 5; i++) {
6 try {
7 Thread.sleep(1000);
8 } catch (InterruptedException e) {
9 e.printStackTrace();
10 }
11 System.out.println("........");
12 }
13 });
14
15 //观察状态
16 Thread.State state = thread.getState();
17 System.out.println(state);
18
19 thread.start();
20 state = thread.getState();
21 System.out.println(state);
22
23 while (state != Thread.State.TERMINATED){
24 Thread.sleep(100);
25 state = thread.getState();
26 System.out.println(state);
27 }
28 }
29}
2.6 线程优先级
进入就绪状态的线程,线程调度器按照优先级决定哪个线程先执行
设置 获取优先级
xxxxxxxxxx
21t2.setPriority(3);
2t2.getPriority()
xxxxxxxxxx
361public class TestPriority {
2
3 public static void main(String[] args) {
4 /*主线程优先级*/
5 System.out.println(Thread.currentThread().getName() + "-->" + Thread.currentThread().getPriority());
6
7 MyPriority myPriority = new MyPriority();
8
9 Thread t1 = new Thread(myPriority,"T1");
10 Thread t2 = new Thread(myPriority,"T2");
11 Thread t3 = new Thread(myPriority,"T3");
12 Thread t4 = new Thread(myPriority,"T4");
13 Thread t5 = new Thread(myPriority,"T5");
14
15 t1.start();
16
17 t2.setPriority(3);
18 t2.start();
19
20 t3.setPriority(5);
21 t3.start();
22
23 t4.setPriority(6);
24 t4.start();
25
26 t5.setPriority(Thread.MAX_PRIORITY);
27 t5.start();
28 }
29}
30
31class MyPriority implements Runnable{
32
33 public void run() {
34 System.out.println(Thread.currentThread().getName() + "-->" + Thread.currentThread().getPriority());
35 }
36}
2.7 守护线程
守护进程创建:
xxxxxxxxxx
11thread.setDaemon(true);
xxxxxxxxxx
351/*测试守护线程*/
2public class TestDaemon {
3 public static void main(String[] args) {
4 God god = new God();
5 You you = new You();
6
7 Thread thread = new Thread(god);
8 thread.setDaemon(true);
9
10 thread.start();
11
12 new Thread(you).start();
13 }
14}
15
16/*God*/
17class God implements Runnable{
18
19 public void run() {
20 while (true){
21 System.out.println("god bless you");
22 }
23 }
24}
25
26/*you*/
27class You implements Runnable{
28
29 public void run() {
30 for (int i = 0; i < 36500; i++) {
31 System.out.println("第" + i + "天");
32 }
33 System.out.println("Goodbye world");
34 }
35}
3 线程同步
3.1 线程同步机制
并发
同一个对象被多个线程同时操作
线程同步
多个线程访问一个对象,并且线程修改对象的值,这时候就需要线程同步,等待机制,多个同时访问对象的线程进入对象的等待池形成队列,一个线程使用完,下一个线程再使用
3.2 并发问题
例子1:抢票 没有线程同步,此时就会出现多个人抢一张票的情况,产生负数
xxxxxxxxxx
251public class Unsafe implements Runnable{
2 private int tickNums = 10;
3
4
5 public void run() {
6 while (tickNums > 0) {
7
8 try {
9 Thread.sleep(200);
10 } catch (InterruptedException e) {
11 e.printStackTrace();
12 }
13
14 System.out.println(Thread.currentThread().getName() + "拿到了第" + tickNums-- + "张票");
15 }
16 }
17
18 public static void main(String[] args) {
19 Unsafe thread = new Unsafe();
20
21 new Thread(thread,"小明").start();
22 new Thread(thread,"老师").start();
23 new Thread(thread,"黄牛").start();
24 }
25}
例子2:多线程插入List,出现重复插入导致数据缺失
xxxxxxxxxx
181public class UnsafeList {
2 public static void main(String[] args) {
3 List<String> List = new ArrayList<>();
4 for (int i = 0; i < 10000; i++) {
5 new Thread(()->{
6 List.add(Thread.currentThread().getName());
7 }).start();
8 }
9
10 try {
11 Thread.sleep(3000);
12 } catch (InterruptedException e) {
13 e.printStackTrace();
14 }
15
16 System.out.println(List.size());
17 }
18}
3.3 同步方法与同步块
同步方法:public synchronized void method()
- synchronized 方法控制对对象的访问,每个对象对应一把锁,每个synchronized 方法都必须获得调用该方法的对象的锁才能执行,方法开始执行,就会独占该锁,直到执行结束才会释放锁,阻塞的线程才能获取这个锁
xxxxxxxxxx
321public class TestSynchronized implements Runnable{
2 private int tickNums = 10;
3 boolean flag = true;
4
5
6 public void run() {
7 while (flag) {
8 try {
9 buy();
10 } catch (InterruptedException e) {
11 e.printStackTrace();
12 }
13 }
14 }
15
16 public synchronized void buy() throws InterruptedException{
17 if (tickNums <= 0) {
18 flag = false;
19 return;
20 }
21 Thread.sleep(100);
22 System.out.println(Thread.currentThread().getName() + "拿到了第" + tickNums-- + "张票");
23 }
24
25 public static void main(String[] args) {
26 TestSynchronized thread = new TestSynchronized();
27
28 new Thread(thread,"小明").start();
29 new Thread(thread,"老师").start();
30 new Thread(thread,"黄牛").start();
31 }
32}
同步块:synchronized(obj){}
obj为同步监视器
- Obj为获取锁的对象,执行同步块时会获取Obj的锁,进行线程同步
- 同步方法默认同步监视器为this,或者为class
xxxxxxxxxx
201public class TestSynList {
2 public static void main(String[] args) {
3 List<String> List = new ArrayList<>();
4 for (int i = 0; i < 10000; i++) {
5 new Thread(()->{
6 synchronized (List){
7 List.add(Thread.currentThread().getName());
8 }
9 }).start();
10 }
11
12 try {
13 Thread.sleep(3000);
14 } catch (InterruptedException e) {
15 e.printStackTrace();
16 }
17
18 System.out.println(List.size());
19 }
20}
3.4 JUC安全类型集合
CopyOnWriteArrayList
类本身能实现线程同步,直接使用
xxxxxxxxxx
181public class TestJUC {
2 public static void main(String[] args) {
3 CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
4 for (int i = 0; i < 10000; i++) {
5 new Thread(()->{
6 list.add(Thread.currentThread().getName());
7 }).start();
8 }
9
10 try {
11 Thread.sleep(3000);
12 } catch (InterruptedException e) {
13 e.printStackTrace();
14 }
15
16 System.out.println(list.size());
17 }
18}
3.5 死锁
死锁的四个必要条件
- 1.互斥条件:一个资源只能被一个进程使用
- 2.请求与保持:一个进程因请求资源而阻塞时,对已有的资源保持不是放
- 3.不剥夺条件:进程已获得的资源,在未使用完之前不进行剥夺
- 4.循环等待:若干进程之间形成头尾相连的循环等待资源的关系
xxxxxxxxxx
611/*死锁*/
2public class DeadLock {
3 public static void main(String[] args) {
4 Makeup q1 = new Makeup(0,"A");
5 Makeup q2 = new Makeup(1,"B");
6
7 q1.start();
8 q2.start();
9 }
10}
11
12class Lipstick{
13
14}
15
16class Mirror{
17
18}
19
20class Makeup extends Thread{
21
22 static Lipstick lipstick = new Lipstick();
23 static Mirror mirror = new Mirror();
24
25 private int choice;
26 private String Name;
27
28 Makeup(int choice,String name){
29 this.choice = choice;
30 this.Name = name;
31 }
32
33
34 public void run() {
35 try {
36 makeup();
37 } catch (InterruptedException e) {
38 e.printStackTrace();
39 }
40 }
41
42 private void makeup() throws InterruptedException {
43 if (choice == 0) {
44 synchronized (lipstick){
45 System.out.println(Name + "获得口红锁");
46 Thread.sleep(1000);
47 synchronized (mirror){
48 System.out.println(Name + "获得镜子锁");
49 }
50 }
51 }else {
52 synchronized (mirror){
53 System.out.println(Name + "获得镜子锁");
54 Thread.sleep(2000);
55 synchronized (lipstick){
56 System.out.println(Name + "获得口红锁");
57 }
58 }
59 }
60 }
61}
3.6 Lock锁
ReentrantLock类实现了Lock,可以显式加锁与释放锁
xxxxxxxxxx
411/*测试Lock锁*/
2public class Lock {
3 public static void main(String[] args) {
4 TestLock L1 = new TestLock();
5
6 new Thread(L1,"L1").start();
7 new Thread(L1,"L2").start();
8 new Thread(L1,"L3").start();
9 }
10}
11
12
13class TestLock implements Runnable{
14
15 private int tickNum = 10;
16 private boolean flag= true;
17
18 /*定义lock锁*/
19 private ReentrantLock lock = new ReentrantLock();
20
21
22 public void run() {
23 while (flag){
24 try {
25 lock.lock();
26 buy();
27 }finally {
28 lock.unlock();
29 }
30 }
31 }
32
33 public void buy(){
34 if (tickNum <= 0) {
35 flag = false;
36 return;
37 }
38
39 System.out.println(Thread.currentThread().getName() + " " +tickNum--);
40 }
41}
4 线程通信
4.1 线程通信方法
wait()
- 线程会一直等待,知道其他线程通知,与sleep不同,会释放锁
- wait可以加参数毫秒,表示指定等待的时间
notify()
- 唤醒一个处于的等待状态的线程
notifyAll()
- 唤醒同一个对象所有调用wait()方法的线程
4.2 管程法
生产者/消费者模型
- 生产者:负责产生数据的模块
- 消费者:负责处理数据的模块
- 缓冲区:生产者将生产好的数据放入缓冲区,消费者从缓冲区拿数据
xxxxxxxxxx
1041/*生产者,消费者,产品,缓冲区*/
2public class TestPC {
3 public static void main(String[] args) {
4 SynContainer container = new SynContainer();
5
6 new Producer(container).start();
7 new Consumer(container).start();
8 }
9}
10
11class Producer extends Thread{
12 SynContainer container;
13
14 public Producer(SynContainer container) {
15 this.container = container;
16 }
17
18 /*生产*/
19
20 public void run() {
21 for (int i = 0; i < 100; i++) {
22 System.out.println("生产了第"+i+"只鸡");
23 container.push(new Chicken(i));
24 }
25 }
26}
27
28class Consumer extends Thread{
29 SynContainer container;
30
31 public Consumer(SynContainer container) {
32 this.container = container;
33 }
34
35 /*生产*/
36
37 public void run() {
38 for (int i = 0; i < 100; i++) {
39 Chicken chicken = container.pop();
40 System.out.println("吃了第"+chicken.getID()+"只鸡");
41 }
42 }
43}
44
45class Chicken{
46 private int ID;
47
48 public Chicken(int ID) {
49 this.ID = ID;
50 }
51
52 public int getID() {
53 return ID;
54 }
55}
56
57class SynContainer{
58 Chicken[] chickens = new Chicken[10];
59 int count = 0;
60
61 /*生产者放入产品*/
62 public synchronized void push(Chicken chicken){
63 /*容器满了,等待消费*/
64 if (count == chickens.length) {
65 try {
66 /*等待消费*/
67 this.wait();
68 } catch (InterruptedException e) {
69 e.printStackTrace();
70 }
71 }
72
73 /*如果容器没满,放入产品*/
74 chickens[count] = chicken;
75 count++;
76
77 /*通知消费者消费*/
78 this.notifyAll();
79 }
80
81 /*消费者取出产品*/
82 public synchronized Chicken pop(){
83 /*判断是否存在产品*/
84 if (count == 0) {
85 try {
86 /*等待生产*/
87 this.wait();
88 } catch (InterruptedException e) {
89 e.printStackTrace();
90 }
91 }
92
93 /*消费者消费*/
94 count--;
95 Chicken chicken = chickens[count];
96 chickens[count] = null;
97
98 /*通知生产者生产*/
99 this.notifyAll();
100
101 return chicken;
102 }
103
104}
4.3 信号灯法
通过一个标志位来判断生产是否完成,消费是否完成
xxxxxxxxxx
921/*信号量*/
2public class TestPC2 {
3 public static void main(String[] args) {
4 TV tv = new TV();
5
6 new Player(tv).start();
7 new Watcher(tv).start();
8 }
9}
10
11/*生产者-->演员*/
12class Player extends Thread{
13 private TV tv;
14
15 public Player(TV tv){
16 this.tv = tv;
17 }
18
19
20 public void run() {
21 for (int i = 0; i < 20; i++) {
22 if (i%2 == 0){
23 tv.play("你所热爱的就是你的生活");
24 }else{
25 tv.play("柠檬什么时候熟");
26 }
27 }
28 }
29}
30
31/*消费者-->观众*/
32class Watcher extends Thread{
33 private TV tv;
34
35 public Watcher(TV tv){
36 this.tv = tv;
37 }
38
39
40 public void run() {
41 for (int i = 0; i < 20; i++) {
42 tv.watch();
43 }
44 }
45}
46
47/*产品-->节目*/
48class TV{
49 /*演员表演,观众等待*/
50 /*观众观看,演员等待*/
51 String voice;
52 boolean flag = true;
53
54 /*表演*/
55 public synchronized void play(String voice){
56
57 if (!flag){
58 try {
59 this.wait();
60 } catch (InterruptedException e) {
61 e.printStackTrace();
62 }
63 }
64
65 System.out.println("演员表演了:"+voice);
66
67 /*通知观众观看*/
68 this.notifyAll();
69 this.voice = voice;
70 this.flag = !this.flag;
71 }
72
73
74 /*观看*/
75 public synchronized void watch(){
76
77 if (flag){
78 try {
79 this.wait();
80 }catch (InterruptedException e) {
81 e.printStackTrace();
82 }
83 }
84 System.out.println("观众观看了:"+voice);
85
86 /*通知演员表演*/
87 this.notifyAll();
88 this.voice = "";
89 this.flag = !this.flag;
90 }
91
92}
5 线程池
提前创建好多个线程,放入线程池,直接获取使用,放回池内
- 提高响应速度
- 降低资源消耗
- 便于管理线程
5.1使用线程池
271/*测试线程池*/
2public class TestThreadPool {
3
4 public static void main(String[] args) {
5 /*1.创建服务,创建线程池*/
6 ExecutorService service = Executors.newFixedThreadPool(10);
7
8 /*执行*/
9 service.execute(new MyThread());
10 service.execute(new MyThread());
11 service.execute(new MyThread());
12 service.execute(new MyThread());
13
14 /*2.关闭链接*/
15 service.shutdown();
16 }
17}
18
19
20class MyThread implements Runnable{
21
22 public void run() {
23 for (int i = 0; i < 10; i++) {
24 System.out.println(Thread.currentThread().getName()+" "+i);
25 }
26 }
27}
posted on 2021-12-03 18:26 Egoistic_Flowers 阅读(30) 评论(0) 编辑 收藏 举报