`
阅读更多

星期日, 十二月 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-多线程 java

    day24-多线程-设计模式.7z

    多线程简单工厂设计模式,工厂方法模式,单列模式,多线程死锁解决

    java_diary_18.rar_JFC_swing_反射机制_国际化 java

    Day11:多线程-进程与线程及方法 Day12:线程机制与I/O流的方法 Day13:I/O流的类与编码方式 Day14:优化的I/O流与网络编程 Day15:网络编程与常用类库 Day16:国际化与新特性 Day17:新特性与并发线程 Day18:软件...

    达内Java培训-CoreJava全程笔记(WORD唐亮版)

    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老师笔记汇总

    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

    多线程,day2,B站狂神,代码Lesson.rar

    CoreJava笔记

    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

    python多线程DAY05.txt

    多进程/多线程并发 : 任何任务 3. 基于fork的多进程并发程序 每当有一个客户端连接就创建一个新的进程 4. ftp文件服务程序 *********************************************** 多线程并发 threading 的多...

    day01-java基础语法.pdf

    Java是一门面向对象编程...Java具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程、动态性等特点 [2] 。Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等 [3] 。

    day11-多线程(1)1

    1.1进程和线程【理解】 1.2实现多线程方式一:继承Thread类【应用】 1.3设置和获取线程名称【应用】 1.4线程优先级【应用】 1.5线程控制【应用】

    python多线程DAY04.txt

    解决了多个进程或者线程对共享资源的争夺 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...

    java学习文档(快速学习-非常使用)

    Day1 一、 从面向过程编程到面向对象编程的思维转变 二、 什么是字节码和虚拟机: 三、 环境变量的设置 四、 kate工具的使用 五、 我们的第一个Java...《多线程》 Day12 一.I/O 流(java 如何实现与外界数据的交流)

    python多线程DAY01.txt

    3.多任务编程 * 并行 和 并发 * 进程 线程 4. 多进程编程 时间片 PCB PID 父子进程 优先级 进程特征 进程状态: 就绪态 运行态 等待态 5. ps -aux ps -ajx pstree top nice 6. os.fork() 7. os.getpid() os....

    python多线程DAY03.txt

    3. 进程池 大量进程事件需要频繁创建删除进程 Pool() apply_async() close() join() map() 4.进程间通信 管道 消息队列 共享内存 信号 信号量 套接字 管道: Pipe() fd.recv() fd.send() 消息队列: ...

    python多线程DAY02.txt

    前情回顾 1. 如何处理僵尸进程 * 通过wait waitpid * 通过创建二级子进程,让一级子进程退出 2. multiprocessing创建进程 * Process 类 创建进程对象 * 通过start启动进程 * 通过join回收子进程 ...

    java视频教程Day01 免费

    11. Multi-Thread(多线程) 12. I/O and File (输入/输出流及文件) 13. Networking (网络编程) 以上教学过程中贯穿一个银行项目,根据每天所学的东西不断完善 J2EE部分 14. JDBC Overview and Using JDBC ...

    python学习day07.txt

    1、多线程爬虫 1、多进程线程应用场景 1、多进程 :大量密集并行计算 2、多线程 :I/O密集(网络I/O、本地磁盘I/O) 2、多线程爬虫 1、URL队列 :put(url) 2、RES队列 :从URL队列中get()发请求,put(html) 3、...

    Java学习路线:day19

    文章目录第8章 多线程线程的生命周期线程的同步同步代码块处理实现Runnable的线程安全问题同步代码块处理继承Thread类的线程安全问题同步方法处理实现Runnable的线程安全问题同步方法处理继承Thread类的线程安全问题...

    Java 2实用教程(第三版)实验指导与习题解答

    上机实践8 多线程 41 实验1 汉字打字练习 41 实验2 旋转的行星 43 实验3 双线程接力 47 上机实践9 输入输出流 50 实验1 学读汉字 50 实验2 统计英文单词字 53 实验2 读取Zip文件 56 上机实践10 Java 中的网络编程 57...

Global site tag (gtag.js) - Google Analytics