星期日, 十二月 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
相关推荐
本课程“day02_eesy_01anno_ioc_多线程”主要聚焦于Spring框架的核心特性——IOC(Inversion of Control,控制反转)以及其在多线程环境下的应用。 首先,让我们深入理解什么是IOC。控制反转是一种设计模式,它将...
Java多线程编程基础知识点 本节课主要讲解了Java多线程编程的基础知识,包括线程的概念、线程与进程的区别、多线程的随机性、Java程序的进程中的线程、线程的创建方式、线程的执行流程、线程内存图等。 1. 进程与...
本资源“day14_多线程01.zip”可能是某个教学课程或者学习资料的一部分,着重讲解了多线程的基础知识和应用。虽然没有具体的标签提供额外信息,但我们可以根据标题和描述来深入探讨多线程这一主题。 多线程是指在一...
"day15_多线程02"这个标题暗示我们将会深入探讨多线程的第二部分,这可能是一个课程或者教程的第十五天内容,重点在于多线程的进阶主题。尽管没有具体的标签,我们可以假设这个压缩包可能包含了源代码、笔记、示例或...
day11-多线程 java
在Java编程语言中,"StringBuffer" 是一个非常重要的类,尤其在处理字符串操作时,尤其是在多线程环境中。在本教程"day13_StringBuffer_java_"中,我们将深入探讨这个类及其在Java中的作用。 Java是C++的优化版本,...
Java的特点包括面向对象、简单性、解释性、高性能、分布式处理、多线程、健壮性、动态、结构中立和安全性等。 Java的简单性体现在它语法上的简洁,对于程序设计来说较为直观易学。解释性指的是Java程序在执行前需要...
4. **多线程**(传智播客_Java培训_毕向东_Java基础[05-多线程].pdf):Java提供了强大的并发支持,多线程编程是其特色之一。这里会涉及线程的创建、同步、协作以及线程安全问题的处理。 5. **集合**(传智播客_...
在“多线程-day02”的学习资源中,我们深入探讨了Java内存模型以及多线程的特性与控制机制。 **Java内存模型** Java内存模型,也称为JVM内存模型,是Java程序员理解和掌握的基础知识,特别是在进行并发编程时。它...
Java多线程是Java编程中的重要概念,它允许程序同时执行多个任务,从而提高系统效率和资源利用率。在Java中,实现多线程有两种主要方式:通过实现`Runnable`接口和继承`Thread`类。 首先,让我们从创建线程开始。当...
在本课程"day24-多线程-设计模式"中,我们将深入探讨如何利用多线程结合设计模式来优化程序执行效率。首先,我们要理解的是,多线程是指在一个进程中同时执行多个线程,从而使得程序能够同时处理多个任务,提升系统...
接着,“day26_21(多线程)JDK5实现线程池.avi”将介绍Java 5及更高版本引入的线程池概念。线程池可以优化系统资源的使用,通过复用已创建的线程来减少创建和销毁线程的开销。Executor框架中的ThreadPoolExecutor是...
"多线程,day2,B站狂神,代码Lesson.rar"这个资源可能是一个关于Java多线程的第二日课程,由B站(哔哩哔哩)上的一位知名编程讲师,也就是所谓的“狂神”,分享的教学材料,包含有实际的代码示例。 首先,我们来...
总的来说,Java Web开发中,Tomcat的学习涵盖了服务器的安装、应用部署、Servlet与JSP编程、错误处理以及性能优化等多个方面。通过深入理解和实践,你将能够熟练地利用Tomcat搭建和管理Java Web应用。
8. **多线程**:学习如何创建和管理线程,理解同步和互斥的概念,以及如何避免线程安全问题。 9. **文件和目录操作**:了解如何在Java中进行文件和目录的创建、删除、重命名等操作。 10. **Java API的使用**:书中...
Java多线程是Java编程中的核心概念,它允许程序同时执行多个任务,极大地提升了程序的效率和响应性。在Java中,多线程主要通过两种方式实现:继承Thread类和实现Runnable接口。下面将深入探讨Java多线程的底层原理、...
线程间的通信和同步是多线程编程中的关键点,例如使用synchronized关键字实现互斥访问,或者使用wait()、notify()和notifyAll()方法控制线程的执行顺序。 此外,文件和I/O操作也是Java开发者必备的技能。Java提供了...
在 Java 中,多线程是并发编程的重要概念,它允许程序同时执行多个任务,从而提高系统效率和资源利用率。在本教程中,我们将探讨多线程的基础知识,包括并发与并行的区别,进程与线程的概念,以及如何在 Java 中创建...
6. **多线程**:Java内置对多线程的支持,可以同时执行多个任务,提升程序效率。 7. **网络编程**:利用Socket编程可以实现客户端和服务器之间的通信。 8. **API和库的使用**:如 Swing 或 JavaFX 用于创建图形用户...
- 类库:Java提供了丰富的标准类库,如集合框架、I/O流、网络编程、多线程等,这些是开发中常用的工具。 4. **开发环境**: - IDE(Integrated Development Environment):如Eclipse、NetBeans、IntelliJ IDEA等...