Java:多线程<三>死锁、线程间通讯
死锁:
同步嵌套同步,而且使用的锁不是同一把锁时就可能出现死锁
class Test implements Runnable
{
private boolean flag;
Test(boolean flag)
{
this.flag = flag;
} public void run()
{
if(flag)
{
while(true)
{
synchronized(MyLock.locka)
{
System.out.println(Thread.currentThread().getName()+"...if locka ");
synchronized(MyLock.lockb)
{
System.out.println(Thread.currentThread().getName()+"..if lockb");
}
}
}
}
else
{
while(true)
{
synchronized(MyLock.lockb)
{
System.out.println(Thread.currentThread().getName()+"..else lockb");
synchronized(MyLock.locka)
{
System.out.println(Thread.currentThread().getName()+".....else locka");
}
}
}
}
}
} class MyLock
{
static Object locka = new Object();
static Object lockb = new Object();
} class DeadLockTest
{
public static void main(String[] args)
{
Thread t1 = new Thread(new Test(true));
Thread t2 = new Thread(new Test(false));
t1.start();
t2.start();
}
}
线程间通讯:
其实就是多线程操作同一个资源,但是操作的动作不同。
例,用多线程操作生成一个人名+性别(男的用英文表示,女的用中文表示),然后打印。
class Res
{
String name;
String sex;
} class Input implements Runnable
{
private Res r;
Input(Res r)
{
this.r = r;
}
public void run()
{
int x = 0;
while(true)
{
synchronized(r)
{
if (x==0)
{
r.name = "Mike";
r.sex="man";
}
else
{
r.name = "丽丽";
r.sex="女";
}
}
x = (x+1)%2;
}
}
} class Output implements Runnable
{
private Res r;
Output(Res r)
{
this.r = r;
}
public void run()
{
while(true)
{
synchronized(r)
{
System.out.println(r.name + "..." +r.sex);
}
}
}
} class ThreadCommunication
{
public static void main(String[] args)
{
Res r = new Res();
Input in = new Input(r);
Output out = new Output(r); Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
t1.start();
t2.start();
}
}注意:1,操作的共同资源必须上锁;2,使用的锁在内存中一定要保证是唯一的;
在上个例子中,并不是按照我们期待的那样,生成一个对象然后打印该对象,即输入一个就输出一个,这就需要用到等待-唤醒机制。
等待-唤醒:
wait:
notify:
notifyall:
都使用在同步中,因为要对持有监视器(锁)的线程操作,所以使用在同步中,因为只有同步才具有锁。
为什么这些操作线程的方法,要定义在Object类中呢?以为你这些方法在操作同步中线程时,都必须要表示它们所操作线程持有的锁。只有同一个锁上的被等待线程可以被同一个锁上的notify唤醒,不可以对不同锁中的线程进行唤醒。也就是说等待和唤醒必须是同一个锁。而锁可以是任意对象,所以被任意对象调用的方法定义在Object中。
class Res
{
String name;
String sex;
Boolean flag=false;
} class Input implements Runnable
{
private Res r;
Input(Res r)
{
this.r = r;
}
public void run()
{
int x = 0;
while(true)
{
synchronized(r)
{
if(r.flag)
{
try
{
r.wait();//如果flag=ture,说明资源中已经有了生产的对象,那么不再生产了,生产线程就wait
}
catch (Exception e)
{
e.printStackTrace();
}
}
if (x==0)
{
r.name = "Mike";
r.sex="man";
}
else
{
r.name = "丽丽";
r.sex="女";
}
r.flag = true;//改变flag标记
r.notify();//唤醒线程池中的第一个等待线程,只在本程序中就是out
}
x = (x+1)%2; }
}
} class Output implements Runnable
{
private Res r;
Output(Res r)
{
this.r = r;
}
public void run()
{
while(true)
{
synchronized(r)
{
if(!r.flag)
{
try
{
r.wait();//如果资源中没有生产对象,那么就没有可以打印的对象,这是输出就wait
}
catch (Exception e)
{
e.printStackTrace();
}
} System.out.println(r.name + "..." +r.sex);
r.flag = false;//改变标记
r.notify();//唤醒线程池中的第一个等待线程,本程序中即in
}
}
}
} class ThreadCommunication
{
public static void main(String[] args)
{
Res r = new Res();
Input in = new Input(r);
Output out = new Output(r); Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
t1.start();
t2.start();
}
}
优化代码
class Res
{
private String name;
private String sex;
private Boolean flag=false; public synchronized void set(String name,String sex)
{
if (flag)
{
try
{
this.wait();
}
catch (Exception e)
{
e.printStackTrace();
}
this.name = name;
this.sex = sex;
flag = ture;
this.notify();
} }
public synchronized void out()
{
if (!flag)
{
try
{
this.wait();
}
catch (Exception e)
{
e.printStackTrace();
}
System.out.println(name + "..." + sex);
flag = false;
this.notify();
}
}
} class Input implements Runnable
{
private Res r;
Input(Res r)
{
this.r = r;
}
public void run()
{
int x = 0;
while(true)
{
synchronized(r)
{
if (x==0)
{
r.set("Mike","man");
}
else
{
r.set("丽丽","女");
}
}
x = (x+1)%2;
}
}
} class Output implements Runnable
{
private Res r;
Output(Res r)
{
this.r = r;
}
public void run()
{
while(true)
{
synchronized(r)
{
r.out();
}
}
}
} class ThreadCommunication
{
public static void main(String[] args)
{
Res r = new Res();
Input in = new Input(r);
Output out = new Output(r); Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
t1.start();
t2.start();
}
}
当多个线程操作同一个资源,且同一个操作也有多个线程时,就需要使用while判断标记,并用notifyAll唤醒所有线程。
class FactoryDemo
{
public static void main(String[] args)
{
Resource r = new Resource();
Product pro = new Product(r);
Consumer con = new Consumer(r);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
} class Product implements Runnable
{
private Resource r = new Resource();
Product(Resource r)
{
this.r = r;
}
public void run()
{
while (true)
{
r.set("商品");
}
}
} class Consumer implements Runnable
{
private Resource r = new Resource();
Consumer(Resource r)
{
this.r = r;
}
public void run()
{
while (true)
{
r.out();
}
}
} class Resource
{
private String name;
private int count = 1;
private boolean flag = false;
public synchronized void set(String name)
{
while (flag)//使用while判断标记,避免线程在判断标记之后醒了不判断标记
{
try
{
this.wait();
}
catch (Exception e)
{
}
}
this.name = name + "--" + count++;
System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
flag = true;
this.notifyAll();
}
public synchronized void out()
{
while (!flag)//使用while判断标记,避免线程在判断标记之后醒了不从新判断标记
{
try
{
wait();
}
catch (Exception e)
{
}
}
System.out.println(Thread.currentThread().getName()+"...消费者.................."+this.name);
flag = false;
this.notifyAll();
}
}
但notifyAll唤醒对方线程的同时也把本方的线程唤醒了,这是我们不希望看到的。对于该问题的优化,参见Lock接口
Java:多线程<三>死锁、线程间通讯的更多相关文章
- (Java多线程系列三)线程间通讯
Java多线程间通讯 多线程之间通讯,其实就是多个线程在操作同一个资源,但是操作的动作不同. 1.使用wait()和notify()方法在线程中通讯 需求:第一个线程写入(input)用户,另一个线程 ...
- java多线程同步以及线程间通信详解&消费者生产者模式&死锁&Thread.join()(多线程编程之二)
本篇我们将讨论以下知识点: 1.线程同步问题的产生 什么是线程同步问题,我们先来看一段卖票系统的代码,然后再分析这个问题: package com.zejian.test; /** * @author ...
- Java多线程编程(6)--线程间通信(下)
因为本文的内容大部分是以生产者/消费者模式来进行讲解和举例的,所以在开始学习本文介绍的几种线程间的通信方式之前,我们先来熟悉一下生产者/消费者模式. 在实际的软件开发过程中,经常会碰到如下场景 ...
- Java多线程编程核心技术---线程间通信(一)
线程是操作系统中独立的个体,但这些个体如果不经过特殊处理就不能成为一个整体.线程间的通信就是成为整体的必用方案之一.线程间通信可以使系统之间的交互性更强大,在大大提高CPU利用率的同时还会使程序员对各 ...
- java多线程三之线程协作与通信实例
多线程的难点主要就是多线程通信协作这一块了,前面笔记二中提到了常见的同步方法,这里主要是进行实例学习了,今天总结了一下3个实例: 1.银行存款与提款多线程实现,使用Lock锁和条件Condition. ...
- Java多线程编程(5)--线程间通信
一.等待与通知 某些情况下,程序要执行的操作需要满足一定的条件(下文统一将其称之为保护条件)才能执行.在单线程编程中,我们可以使用轮询的方式来实现,即频繁地判断是否满足保护条件,若不满足则继续判断 ...
- Java多线程编程核心技术---线程间通信(二)
通过管道进行线程间通信:字节流 Java提供了各种各样的输入/输出流Stream可以很方便地对数据进行操作,其中管道流(pipeStream)是一种特殊的流,用于在不同线程间直接传送数据,一个线程发送 ...
- java多线程5:线程间的通信
在多线程系统中,彼此之间的通信协作非常重要,下面来聊聊线程间通信的几种方式. wait/notify 想像一个场景,A.B两个线程操作一个共享List对象,A对List进行add操作,B线程等待Lis ...
- java 多线程6(线程的·通讯)
问题1: 为什么wait() 和 notify()是Object类中的方法,而不是Thread类中的方法呢? 答:因为锁是任意对象的所以要在Object类中,如果在Thread类中锁对象不是任意的了. ...
- C++多线程编程(三)线程间通信
多线程编程之三——线程间通讯 作者:韩耀旭 原文地址:http://www.vckbase.com/document/viewdoc/?id=1707 七.线程间通讯 一般而言,应用程序中的一个次要线 ...
随机推荐
- JDBC连接mysql数据库,添加数据
如下:其中添加/删除/修改只是sql字符串不同 //3.要执行的字符串 String sql="INSERT INTO t_student(NAME,age,email) VALUES('x ...
- paper 99:CV界的明星人物经典介绍
CV人物1:Jianbo Shi史建波毕业于UC Berkeley,导师是Jitendra Malik.其最有影响力的研究成果:图像分割.其于2000年在PAMI上多人合作发表”Nor ...
- Dynamics AX 2012 R2 AIF自定义服务中的事务回滚Bug
Reinhard在一个Customer Service里的一个Method中,发现一个Transcation RollBack Bug.先看该Method的代码: [SysEntryPointAttr ...
- Lucene学习总结
在使用Lucene前,我们先大致熟悉下Lucene的几个核心类. 核心索引类: public class IndexWriter 索引过程的中心组件,把它想象成一个可以对索引进行写操作的对象. pub ...
- 结合Apache和Tomcat实现集群和负载均衡 JK 方式
本文基本参考自 轻松实现Apache,Tomcat集群和负载均衡,经由实操经历记录而成,碰到些出入,以及个别地方依据个人的习惯,所以在一定程度上未能保持原文的完整性,还望原著者海涵. 因原文中有较多的 ...
- easyui dialog 扩展load
$.extend($.fn.panel.methods, { showMask: function(jq, msg){ return jq.each(function(){ var pal = $(t ...
- C#获取文件时间
在NTFS下,文件的创建及修改时间可以精确到毫秒,以下是测试过程. DirectoryInfo diSource = new DirectoryInfo(@"C:\Users\不告诉你\De ...
- spark调试
http://blog.csdn.net/shenlanzifa/article/details/42679577 http://alvinalexander.com/java/jwarehouse/ ...
- 从零开始学iPhone开发(1)——工具的使用
前提:已经具备了苹果电脑或者iMac,或者安装好了x86苹果而且已经联网. 苹果系统版本要求是:Max OS X Lion,或者 Mountain Lion 我们对iPhone进行使用的工具是XCod ...
- Spring中处理Post方法中文乱码
在Web.xml中配置: <!-- 注册Spring提供的处理Post请求的乱码问题 --> <filter> <filter-name>CharacterEnco ...