进阶Java编程(3)线程的同步与死锁
线程的同步与死锁
1,同步问题引出
在多线程的处理之中,可以利用Runnable描述多个线程操作的资源,而Thread描述每一个线程对象,对于当多个线程访问统一资源的时候如果处理不当就会产生数据的错误操作。
①同步问题的引出
下面编写一个买票程序,将创建若干个线程的对象实现卖票处理操作。
·范例:实现卖票操作
class MyThread implements Runnable{
private int ticket=10;//总票数为10张
@Override
public void run() {
while (true){
if(this.ticket>0){
try{
Thread.sleep(100);
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖票,ticket="+this.ticket--);
}else {
System.out.println("****** 票已经卖光了 *********");
break;
}
}
}
}
public class Main {
public static void main(String[] args) {
MyThread myThread=new MyThread();
new Thread(myThread,"票贩子A").start();
new Thread(myThread,"票贩子B").start();
new Thread(myThread,"票贩子C").start();
new Thread(myThread,"票贩子D").start();
new Thread(myThread,"票贩子E").start();
}
}
票贩子A卖票,ticket=0
****** 票已经卖光了 *********
票贩子B卖票,ticket=1
****** 票已经卖光了 *********
票贩子C卖票,ticket=-2
****** 票已经卖光了 *********
票贩子D卖票,ticket=-3
****** 票已经卖光了 *********
****** 票已经卖光了 *********
此时的程序将创建三个线程对象,并且这三个线程对象将进行5章票的出售。此时的程序在进行卖票处理的时候并没有任何的问题(这是假象),下面可以模拟一下卖票过程中的延迟操作。

2,线程同步处理
经过分析之后已经可以确定同步问题所产生的主要原因了,那么下面就需要进行进行同步问题的关键是锁,指的是当某一个线程执行操作的时候,其他线程外面等待;

如果想要在程序之中实现这把锁的功能,就可以使用synchronized关键字来实现,利用此关键字可以定义同步方法或同步代码块,在同步代码块的操作里面的代码只允许一个线程执行。
①利用同步代码块进行处理:
synchronized (同步操作){
同步代码操作;
}
·范例:利用同步代码块解决数据同步访问问题一般要进行同步对象处理的时候可以采用当前对象this进行同步。
class MyThread implements Runnable{
private int ticket=10;//总票数为10张
@Override
public void run() {
while (true){
synchronized(this){//每一次只允许一个线程进行执行
if(this.ticket>0){
try{
Thread.sleep(100);
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖票,ticket="+this.ticket--);
}else {
System.out.println("* 票已经卖光了 *");
break;
}
}
}
}
}
public class Main {
public static void main(String[] args) {
MyThread myThread=new MyThread();
new Thread(myThread,"票贩子A").start();
new Thread(myThread,"票贩子B").start();
new Thread(myThread,"票贩子C").start();
}
}
②利用同步方法解决:只需要在方法定义上使用synchronized关键字即可加入同步处理之后,程序的整体的执行的性能下降了。同步实际上会造成性能的降低。
class MyThread implements Runnable{
private int ticket=10;//总票数为10张
public synchronized boolean sale(){
if(this.ticket>0){
try{
Thread.sleep(100);
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖票,ticket="+this.ticket--);
return true;
}else {
System.out.println("****** 票已经卖光了 *********");
return false;
}
}
@Override
public void run() {
while (this.sale()){
;//空语句
}
}
}
public class Main {
public static void main(String[] args) {
MyThread myThread=new MyThread();
new Thread(myThread,"票贩子A").start();
new Thread(myThread,"票贩子B").start();
new Thread(myThread,"票贩子C").start();
}
}
在日后学习Java类库的时候会发现,系统中使用的类上使用的许多同步处理采用的都是同步方法。
注意:同步会造成性能的下降,并发才会高性能。
3,线程死锁
死锁是在进行多线程同步的处理之中有可能产生的一种问题,所谓的死锁指的是若干个线程彼此互相等待的状态。
·范例:通过一个简单的代码观察死锁
public class DeadLock implements Runnable{
private Jian jj =new Jian();
private XiaoQiang xq=new XiaoQiang();
@Override
public void run() {
jj.say(xq);
}
public DeadLock(){//构造方法
new Thread(this).start();
xq.say(jj);
}
public static void main(String[] args) {
new DeadLock();
}
}
class Jian{
public synchronized void say(XiaoQiang xq){
System.out.println("阿建说:此路是我开留下买路财");
xq.get();
}
public synchronized void get(){
System.out.println("阿建说:获得过路费买饭吃");
}
}
class XiaoQiang{
public synchronized void say(Jian jj){
System.out.println("小强说:先过路在给钱");
jj.get();
}
public synchronized void get(){
System.out.println("小强说:通过道路去上班");
}
}
若干线程访问同一资源时一定要进行同步处理,而过多的同步会造成死锁。现在死锁造成的主要原因是因为彼此都在互相等待着,等待着对方先让出资源。死锁是开发中的一种不确定的状态,有的时候代码处理不当则会不定期出现死锁,这是属于正常开发中的调试问题。
进阶Java编程(3)线程的同步与死锁的更多相关文章
- 进阶Java编程(2)线程常用操作方法
线程常用操作方法 多线程的主要操作方法都在Thread类中定义的. 1,线程的命名和取得 多线程的运行状态是不确定的,那么在程序的开发之中为了可以获取到一些需要使用到的线程就只能依靠线程的名字来进行操 ...
- Java并发编程:线程的同步
Java并发编程:线程的同步 */--> code {color: #FF0000} pre.src {background-color: #002b36; color: #839496;} J ...
- Java多线程之线程的同步
Java多线程之线程的同步 实际开发中我们也经常提到说线程安全问题,那么什么是线程安全问题呢? 线程不安全就是说在多线程编程中出现了错误情况,由于系统的线程调度具有一定的随机性,当使用多个线程来访问同 ...
- 菜鸡的Java笔记 - java 线程的同步与死锁 (同步 synchronization,死锁 deadlock)
线程的同步与死锁 (同步 synchronization,死锁 deadlock) 多线程的操作方法 1.线程同步的产生与解决 2.死锁的问题 ...
- java多线程之线程的同步与锁定(转)
一.同步问题提出 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏. 例如:两个线程ThreadA.ThreadB都操作同一个对象Foo对象,并修改Foo对象上的数据. publicc ...
- 进阶Java编程(1)多线程编程
Java多线程编程 1,进程与线程 在Java语言里面最大的特点是支持多线程的开发(也是为数不多支持多线程的编程语言Golang.Clojure方言.Elixir),所以在整个的Java技术学习里面, ...
- 进阶Java编程(13)反射与Annotation
1,反射取得Annotation信息 从JDK1.5之后Java提供了Annotation技术支持,这种技术为项目的编写带来了新的模型,而后经过了十年的发展,Annotation的技术得到了非常广泛的 ...
- 进阶Java编程(10)反射与简单Java类
1,传统属性自动赋值弊端 简单Java类主要由属性构成,并且提供有setter与getter类,同时简单Java类最大的特征就是通过对象保存相应的类属性的内容.但是如果使用传统的简单Java类开发,那 ...
- 进阶Java编程(5)基础类库
Java基础类库 1,StringBuffer类 String类是在所有项目开发之中一定会使用到的一个功能类,并且这个类拥有如下的特点: ①每一个字符串的常量都属于一个String类的匿名对象,并且不 ...
随机推荐
- Leetcode题目139.单词拆分(动态规划-中等)
题目描述: 给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词. 说明: 拆分时可以重复使用字典中的单词.你可以假设字典 ...
- Docker+Rancher构建部署流水线
工作多年,在项目部署方面, 1:以前用ftp或者rz上传更新的,每次更新算上打包.目录切换.更新遗漏.备份.出错还原.启动等工作都得搞上一来小时甚至更长,要是多两台服务器那心都凉了: 2:后来有用sv ...
- Nginx之最简单的反向代理机制分析
注:当前分析基于 Nginx之搭建反向代理实现tomcat分布式集群 的配置. 1. 用到的指令 下面介绍在上面的配置中用到的指令. upstream 指令 语法:upstream name { .. ...
- 【软件工程】Beta冲刺(5/5)
链接部分 队名:女生都队 组长博客: 博客链接 作业博客:博客链接 小组内容 恩泽(组长) 过去两天完成了哪些任务 描述 将数据分析以可视化形式展示出来 新增数据分析展示等功能API 服务器后端部署, ...
- ionic3引用外部插件--百度地图及echart报表的使用
前言 ionic3提供的组件已经相当丰富咯,但是事实上有些特殊的需求,比如使用百度地图,或者第三方插件echart报表插件是,就不能用传统的方式去使用第三方插件咯,如何在Ionic3项目中使用第三方J ...
- QT Embedded二三事之QObject的元对象
一.元对象 元对象被称做是meta object.在运行时刻(runtime),能够提供对象的运行时信息. 在C++语言发展的早期,C++语言本身没有定义对象的运行时信息,如输出类的名 ...
- Android跨进程通信广播(Broadcast)
广播是一种被动跨进程通讯的方式.当某个程序向系统发送广播时,其他的应用程序只能被动地接收广播数据.这就象电台进行广播一样,听众只能被动地收听,而不能主动与电台进行沟通,在应用程序中发送广播比较简单.只 ...
- C#计算两个时间年份月份天数(根据生日计算年龄)差,求时间间隔
C#计算两个时间年份月份差 DateTime dt1 = Convert.ToDateTime("2008-8-8"); DateTime dt2 = System.DateTim ...
- Nginx URL重写(rewrite)配置及信息详解
URL重写有利于网站首选域的确定,对于同一资源页面多条路径的301重定向有助于URL权重的集中 Nginx URL重写(rewrite)介绍 和apache等web服务软件一样,rewrite的组要功 ...
- Myeclipse 启动tomcat项目报Out of memory: java heap space
问题: 在Myeclipse中启动tomcat,程序启动过程中报内存不足,java.lang.OutOfMemoryError: Java heap space 从错误可以看出是堆内存太小,需要配置j ...