Java学习路线-15:多线程的同步与死锁
第3 章 : 线程的同步与死锁
14 同步问题引出
Thread描述每一个线程对象
Runnable描述多个线程操作的资源
多个线程访问同一资源的时候,如果处理不当会产生数据错误
3个线程卖票程序,会出现多张同号的票
class MyThread implements Runnable { private int ticket = 10; @Override public void run() { while (true) { if (this.ticket > 0) { System.out.println( Thread.currentThread().getName() + "卖第" + this.ticket + " 张票" ); this.ticket--; } else { System.out.println("票卖光了"); break; } } }
}
public class Demo { public static void main(String[] args) { MyThread thread = new MyThread(); new Thread(thread).start(); new Thread(thread).start(); new Thread(thread).start(); // 5 }
}
- 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
15 线程同步处理
同步:多个操作在同一时间段内只能有一个线程进行,
其他线程要等待此线程完成之后才可以继续还行
解决同步问题的方式是锁
synchronized定义同步方法或同步代码块,里边的代码只允许一个线程执行
加入同步之后,程序整体性能下降了
1、同步代码块
synchronized(同步对象){}
- 1
举例
synchronized (this) { if (this.ticket > 0) { System.out.println(Thread.currentThread().getName() + "卖第" + this.ticket + " 张票"); this.ticket--; } else { System.out.println("票卖光了"); break; }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
2、同步函数
public synchronized boolean method(){}
- 1
举例
public synchronized boolean sale(){ if (this.ticket > 0) { System.out.println(Thread.currentThread().getName() + "卖第" + this.ticket + " 张票"); this.ticket--; return true; } else { System.out.println("票卖光了"); return false; }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
16 线程死锁
死锁是在进行多线程同步处理之中有可能产生的一种问题
是指若干个线程彼此互相等待的状态
若干线程访问同一资源时,一定要进行同步处理
而过多的同步会造成死锁
public class Demo { public static void main(String[] args) { //o1 o2 代表资源 Object o1 = new Object(); Object o2 = new Object(); System.out.println("go go go!"); Thread t1 = new Thread(new Runnable() { public void run() { synchronized (o1) { //线程t1获取o1的锁才能继续执行 try { Thread.sleep(3000); //睡3秒,确保线程t2把o2锁拿走 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("t1获得了哦O1"); synchronized (o2) { //线程t1获取o2的锁才能继续执行 System.out.println("t1获得了哦O2"); } } } }); Thread t2 = new Thread(new Runnable() { public void run() { synchronized (o2) { //线程t2获取o2的锁才能继续执行 try { Thread.sleep(3000); //睡3秒,确保线程t1把o1锁拿走 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("t2获得了哦O2"); synchronized (o1) { //线程t2获取o1的锁才能继续执行 System.out.println("t2获得了哦O1"); } } } }); t1.start(); t2.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
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
第4 章 : 综合实战:“生产者-消费者”模型
17 生产者与消费者基本程序模型
生产者负责信息内容生产
消费者取走信息
消费者要等待生产者生产完成再取走
生产者需要等待消费者消费完成再生产
不加锁示例
class Message { private String content; public void setContent(String content) { this.content = content; } public String getContent() { return content; }
}
class Producer implements Runnable { private Message message; private static int count; public Producer(Message message) { this.message = message; } @Override public void run() { for (int i = 0; i < 10; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } this.message.setContent("这是第" + count + " 个消息"); count++; } }
}
class Consumer implements Runnable { private Message message; public Consumer(Message message) { this.message = message; } @Override public void run() { for (int i = 0; i < 10; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(this.message.getContent()); } }
}
class Demo { public static void main(String[] args) { Message message = new Message(); new Thread(new Producer(message)).start(); new Thread(new Consumer(message)).start(); }
}
/**
这是第0 个消息
这是第0 个消息
这是第1 个消息
这是第2 个消息
这是第3 个消息
这是第4 个消息
这是第5 个消息
这是第6 个消息
这是第7 个消息
这是第8 个消息
*/
- 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
18 解决生产者-消费者同步问题
增加关键字 synchronized
19 利用Object类解决重复操作
等待机制
(1)一直等待
public final void wait()
- 1
(2)等待一段时间
public final native void wait(long timeout)
- 1
唤醒线程
(1)唤醒一个等待线程, 唤醒第一个等待的线程
public final native void notify();
- 1
(2)唤醒全部等待线程,谁优先级高谁先执行
public final native void notifyAll();
- 1
完整代码
class Message { private String content; private boolean flag = false; // 生产完成就为true public synchronized void setContent(String content) { if (this.flag == true) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } this.content = content; this.flag = true; notify(); } public synchronized String getContent() { if (this.flag == false) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } try { return content; } finally { this.flag = false; notify(); } }
}
class Producer implements Runnable { private Message message; private static int count; public Producer(Message message) { this.message = message; } @Override public void run() { for (int i = 0; i < 10; i++) { this.message.setContent("这是第" + count + " 个消息"); count++; } }
}
class Consumer implements Runnable { private Message message; public Consumer(Message message) { this.message = message; } @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(this.message.getContent()); } }
}
class Demo { public static void main(String[] args) { Message message = new Message(); new Thread(new Producer(message)).start(); new Thread(new Consumer(message)).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
- 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
第5 章 : 多线程深入话题
20 优雅的停止线程
已废除的方法,可能会导致线程死锁,不建议使用
// 停止线程
public final void stop()
// 销毁线程
public void destroy()
// 挂起线程
public final void suspend()
// 恢复线程
public final void resume()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
使用flag 标志位不会立刻停止,而是当前线程自己判断
class Demo{ private static boolean flag = true; public static void main(String[] args) { new Thread(()->{ while (flag){ try { Thread.sleep(600); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"正在执行"); } }, "自定义线程").start(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("时间到"); flag = false; }
}
- 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
21 后台守护线程
守护线程,如果主线程退出,守护线程就退出
GC就是守护线程
设置为守护线程
public final void setDaemon(boolean on)
- 1
判断是否为守护线程
public final boolean isDaemon()
- 1
示例
设置线程为守护线程后,主程序执行完毕就退出了,并不会打印任何内容
class MyThread implements Runnable{ @Override public void run() { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" 正在执行"); }
}
class Demo{ public static void main(String[] args) { Thread t = new Thread(new MyThread()); t.setDaemon(true); t.start(); }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
22 volatile关键字
volatile 用于属性定义, 中文意思:易变的
变量处理的步骤:
(1)获取变量原有的数据内容副本
(2)利用副本为变量进行数学计算
(3)建计算后的变量,保存到原始空间中
读取read <- 数据副本
加载load
使用use
赋值asign
存储store
写入write -> 原始空间
- 1
- 2
- 3
- 4
- 5
- 6
属性上加了volatile, 没有中间拷贝过程,直接使用原始数据
区别:volatile 和 synchronized
volatile: 主要在属性上使用,无法描述同步,直接内存处理,避免副本操作
synchronized: 代码块与方法上使用
class MyThread implements Runnable{ private volatile int count = 10; @Override public void run() { while (count>0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" 正在执行"); count --; } }
}
class Demo{ public static void main(String[] args) { Thread t = new Thread(new MyThread()); t.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
文章来源: pengshiyu.blog.csdn.net,作者:彭世瑜,版权归原作者所有,如需转载,请联系作者。
原文链接:pengshiyu.blog.csdn.net/article/details/103059816
- 点赞
- 收藏
- 关注作者
评论(0)