星期日, 十二月 06, 2015 21:52:16
五、多线程的同步
本节介绍多线程的同步,具体介绍同步问题的引出、同步代码块、同步方法和死锁等内容。
5.1同步问题的引出
重现问题,可以在程序中调用Thread.sleep()静态方法来刻意造成线程间的这种切换。
Thread.sleep()方法将迫使线程执行到该处后暂停执行,让出cpu给别的线程,在指定的时间后,cpu回到刚才暂停的线程上执行。
5.1线程同步问题
代码案例:
package day34; public class ThreadTb { public static void main(String[] args) { /*模拟铁路售票系统的范例,实现4个售票发售某日某次列车的车票20张, 一个售票点用一个线程来表示。*/ ThreadT tp = new ThreadT(); //启动4个线程,并实现了资源共享的目的 new Thread(tp).start(); new Thread(tp).start(); new Thread(tp).start(); new Thread(tp).start(); } } class ThreadT implements Runnable { private int tickets = 20; @Override public void run() { // TODO Auto-generated method stub while(true) { if(tickets>0) { try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"..."+(tickets--)); } } } } 运行结果: 部分 Thread-2...6 Thread-1...7 Thread-3...4 Thread-1...2 Thread-2...3 Thread-0...1 Thread-1...0 Thread-3...-1 Thread-2...-2
注意:
1.程序中使用sleep()以让出cpu给别的线程。出现了负数
2.造成这种意外的根本原因就是因为资源数据访问不同步引起的。
5.2解决方法 : 同步代码块
必须保证这段代码的原子性
即当一个线程运行到if(tickets>0)后,cpu不去执行其他线程中的、可能影响当前线程中的下一句代码的执行结果的代码块,
必须等到下一句执行完后才能执行其他线程中的有关代码块。
这段代码就好比一座独木桥,任何时刻都只能有一个人在桥上走,即程序中不能有多个线程同时在这两句代码之间执行,
即线程同步。
语法:
synchronized(对象){
需要同步的代码;
}
5.2.1 修改后的代码
package day34; public class ThreadSync { public static void main(String[] args) { /*模拟铁路售票系统的范例,实现4个售票发售某日某次列车的车票20张, 一个售票点用一个线程来表示。*/ ThreadT tp = new ThreadT(); //启动4个线程,并实现了资源共享的目的 new Thread(tp).start(); new Thread(tp).start(); new Thread(tp).start(); new Thread(tp).start(); } } class ThreadT implements Runnable { private int tickets = 20; @Override public void run() { // TODO Auto-generated method stub while(true) { synchronized(this){ if(tickets>0) { try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"..."+(tickets--)); } } } } } 运行结果: 部分 Thread-3...3 Thread-3...2 Thread-3...1
总结:
本程序将这些需要具有原子性的代码放入synchronized语句内,形成了同步代码块。
在同一时刻只能有一个线程可以进入同步代码块内运行,只有当该线程离开同步代码块后,其他线程才能进入同步代码内运行。
5.3同步方法
除了可以对代码块进行同步外,也可以对方法实现同步,只要在需要同步的方法定义前面加上synchronized关键字即可。
语法:
访问控制符 synchronized 返回值类型 方法名称(参数){}
代码案例:
package day34; public class ThreadSync { public static void main(String[] args) { /*模拟铁路售票系统的范例,实现4个售票发售某日某次列车的车票20张, 一个售票点用一个线程来表示。*/ ThreadT tp = new ThreadT(); //启动4个线程,并实现了资源共享的目的 new Thread(tp).start(); new Thread(tp).start(); new Thread(tp).start(); new Thread(tp).start(); } } class ThreadT implements Runnable { private int tickets = 20; @Override public void run() { // TODO Auto-generated method stub while(true) { sale(); } } public synchronized void sale() { if(tickets>0) { try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"..."+(tickets--)); } } } 运行结果: Thread-0...5 Thread-3...4 Thread-2...3 Thread-1...2 Thread-1...1
注意:
在同一类中,使用synchronized关键字定义的若干方法,可以在多线程之间同步。
当有一个线程进入有synchronized修饰的方法时,其他线程就不能进入同一个对象使用synchronized来修饰所以方法,
直到第1个线程执行完它所进入的synchronized修饰的方法为止。
5.4死锁
一旦有多个进程,且它们都要争用对多个锁的独占访问,那么就有可能发生死锁。
如果有一组进程或线程,其中每个都在等待一个只有其他进程或线程才可以进行的操作,
那么就称为死锁了。
要避免死锁,应该确保在获取多个锁时,在所有的线程中都以相同的顺序获取锁。
5.4.1代码案例
package day34; public class DeadLock implements Runnable{ A a = new A(); B b = new B(); DeadLock(){ Thread.currentThread().setName("main--->thread"); Thread tt = new Thread(this); tt.start(); a.funA(b); System.out.println("main线程运行完毕"); } @Override public void run() { // TODO Auto-generated method stub Thread.currentThread().setName("Test--->thread"); b.funB(a); System.out.println("其他线程运行完毕"); } public static void main(String[] args) { new DeadLock(); } } class A{ synchronized void funA(B b) { System.out.println(Thread.currentThread().getName()+"进入A"); try { Thread.sleep(10000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); System.out.println(Thread.currentThread().getName()+"调用B类中的last()方法"); b.last(); } } synchronized void last(){ System.out.println("A类中的last()方法"); } } class B{ synchronized void funB(A a) { System.out.println(Thread.currentThread().getName()+"进入B"); try { Thread.sleep(10000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); System.out.println(Thread.currentThread().getName()+"调用A类中的last()方法"); a.last(); } } synchronized void last(){ System.out.print("B类中的last()方法"); } } 运行结果: main--->thread进入A Test--->thread进入B 其他线程运行完毕 main线程运行完毕
需要分析原因,运行结果有疑问
分析:
Test-->thread 进入b的监视器,然后又等待a的监视器。
同时main-->thread进入了a的监视器,并等待b的监视器。
这个程序永远不会完成。
星期日, 十二月 06, 2015 23:02:34
371--381
相关推荐
day11-多线程 java
多线程简单工厂设计模式,工厂方法模式,单列模式,多线程死锁解决
Day11:多线程-进程与线程及方法 Day12:线程机制与I/O流的方法 Day13:I/O流的类与编码方式 Day14:优化的I/O流与网络编程 Day15:网络编程与常用类库 Day16:国际化与新特性 Day17:新特性与并发线程 Day18:软件...
CoreJava DAY01 Java概述 1 CoreJava DAY02 数据类型和控制结构 6 CoreJava DAY03 数组 11 CoreJava DAY04 15 ...CoreJava DAY19-20 多线程 85 CoreJava DAY21-22 IO 95 CoreJava DAY23 网络编程 107
CoreJava DAY01 Java概述 1 CoreJava DAY02 数据类型和控制结构 10 CoreJava DAY03 数组 20 CoreJava DAY04 27 ...CoreJava DAY19-20 多线程 154 CoreJava DAY21-22 IO 174 CoreJava DAY23 网络编程 197
多线程,day2,B站狂神,代码Lesson.rar
CoreJava笔记 CoreJava DAY01 Java概述 1 CoreJava DAY02 数据类型和控制结构 6 CoreJava DAY03 数组 11 CoreJava DAY04 15 ...CoreJava DAY19-20 多线程 85 CoreJava DAY21-22 IO 95 CoreJava DAY23 网络编程 107
多进程/多线程并发 : 任何任务 3. 基于fork的多进程并发程序 每当有一个客户端连接就创建一个新的进程 4. ftp文件服务程序 *********************************************** 多线程并发 threading 的多...
Java是一门面向对象编程...Java具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程、动态性等特点 [2] 。Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等 [3] 。
1.1进程和线程【理解】 1.2实现多线程方式一:继承Thread类【应用】 1.3设置和获取线程名称【应用】 1.4线程优先级【应用】 1.5线程控制【应用】
解决了多个进程或者线程对共享资源的争夺 Event e.set e.clear e.wait Lock lock.acquire() lock.release() 4. 什么是线程 threading Thread() t.start() t.join() t.name t.getName t.setName t.daemon...
Day1 一、 从面向过程编程到面向对象编程的思维转变 二、 什么是字节码和虚拟机: 三、 环境变量的设置 四、 kate工具的使用 五、 我们的第一个Java...《多线程》 Day12 一.I/O 流(java 如何实现与外界数据的交流)
3.多任务编程 * 并行 和 并发 * 进程 线程 4. 多进程编程 时间片 PCB PID 父子进程 优先级 进程特征 进程状态: 就绪态 运行态 等待态 5. ps -aux ps -ajx pstree top nice 6. os.fork() 7. os.getpid() os....
3. 进程池 大量进程事件需要频繁创建删除进程 Pool() apply_async() close() join() map() 4.进程间通信 管道 消息队列 共享内存 信号 信号量 套接字 管道: Pipe() fd.recv() fd.send() 消息队列: ...
前情回顾 1. 如何处理僵尸进程 * 通过wait waitpid * 通过创建二级子进程,让一级子进程退出 2. multiprocessing创建进程 * Process 类 创建进程对象 * 通过start启动进程 * 通过join回收子进程 ...
11. Multi-Thread(多线程) 12. I/O and File (输入/输出流及文件) 13. Networking (网络编程) 以上教学过程中贯穿一个银行项目,根据每天所学的东西不断完善 J2EE部分 14. JDBC Overview and Using JDBC ...
1、多线程爬虫 1、多进程线程应用场景 1、多进程 :大量密集并行计算 2、多线程 :I/O密集(网络I/O、本地磁盘I/O) 2、多线程爬虫 1、URL队列 :put(url) 2、RES队列 :从URL队列中get()发请求,put(html) 3、...
文章目录第8章 多线程线程的生命周期线程的同步同步代码块处理实现Runnable的线程安全问题同步代码块处理继承Thread类的线程安全问题同步方法处理实现Runnable的线程安全问题同步方法处理继承Thread类的线程安全问题...
上机实践8 多线程 41 实验1 汉字打字练习 41 实验2 旋转的行星 43 实验3 双线程接力 47 上机实践9 输入输出流 50 实验1 学读汉字 50 实验2 统计英文单词字 53 实验2 读取Zip文件 56 上机实践10 Java 中的网络编程 57...