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 七.线程间通讯 一般而言,应用程序中的一个次要线 ...
随机推荐
- angular懒加载机制 刷新后无法回退解决方案
今天在项目中遇到一个很奇怪的问题,使用oclazyload来懒加载angular的模块,刷新页面后,单击回退按钮无法返回上一个页面.估计是使用懒加载机制销毁了angular内部的state关联,导致无 ...
- 解决SVN不显示状态图标
打开注册表,找到"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlay ...
- -Xmx 和 –Xms 设置最大堆和最小堆
C:\Java\jre1.6.0\bin\javaw.exe 按照上面所说的,最后参数在eclipse.ini中可以写成这个样子: -vmargs -Xms128M -Xmx512M ...
- 【001:转载 ubuntu下: 建立本地SVN服务器】
1.安装 svn 工具 $sudo apt-get install subversion 2. 创建工程文件夹,用于存放工程 $mkdir ~/localsvn $mkdir ~/localsvn/ ...
- 记录对依赖注入的小小理解和autofac的简单封装
首先,我不是一个开发者,只是业余学习者.其次我的文化水平很低,写这个主要是记录一下当前对于这块的理解,因为对于一个低水平 的业余学习者来说,忘记是很平常的事,因为接触.应用的少,现在理解,可能过段时间 ...
- Windows Azure Azure 简介
平台介绍 Windows Azure作为一个微软公有云平台,被寄予了厚望. 可以说Windows Azure与Windows RT一样是微软战略转型的重点. 2012年9月微软与中国本土的电信服务提供 ...
- Mvc请求管道中的19个事件
下面是请求管道中的19个事件. (1)BeginRequest: 开始处理请求 (2)AuthenticateRequest授权验证请求,获取用户授权信息 (3):PostAuthenticateRe ...
- 机器学习实战-边学边读python代码(3)
程序清单2-3 归一化特征值: def autoNorm(dataSet): /* >>> barray([[ 1., 2., 3.], [ 2., 3., 4.], [ 10., ...
- SVN使用教程总结
SVN简介: 为什么要使用SVN? 程序员在编写程序的过程中,每个程序员都会生成很多不同的版本,这就需要程序员有效的管理代码,在需要的时候可以迅速,准确取出相应的版本. Subversion是什么? ...
- myisam压缩(前缀压缩)索引
myisam使用前缀压缩来减少索引的大小,从而让更多的索引可以放入内存中,默认只压缩字符串,但通过参数配置也可以对整数做压缩,myisam压缩每个索引块的方法是,先完全保存索引块中的第一个值,然后将其 ...