线程同步、死锁和通信——Java多线程(二)
一、多线程同步
上一篇随笔中,我曾遇到对多线程程序的多次运行结果不一致的情况,这主要是因为没有对这些线程在访问临界资源做必要的控制,而接下来就用线程的同步来解决这个问题。
1.同步代码块
class RunnableDemo implements Runnable
{
private int tickets=5;
public void run()
{
while(true)
{
synchronized(this)//同步代码块语法定义如下
{
if(tickets<=0) break;
try{
Thread.sleep(100);
}
catch(Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"出售票:"+tickets);
tickets -= 1;
}
}
}
} public class ThreadTest
{
public static void main(String[] args)
{
RunnableDemo r = new RunnableDemo();
new Thread(r).start();
new Thread(r).start();
new Thread(r).start();
new Thread(r).start();
}
}
在同一时刻只能由一个线程进入同步代码块内运行,只有当该线程离开同步代码块后,其他线程才能进入同步代码块内运行。
2.同步方法
即:把上述例子中同步代码块的内容,专门封装在一个方法里,通过在run()方法中调用创建的方法实现相应的功能。
class RunnableDemo implements Runnable
{
private int tickets=5;
public void run()
{
while(tickets>0)
{
sale();
}
}
public synchronized void sale()//同步方法
{
if(tickets>0){
try{
Thread.sleep(100);
}
catch(Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"出售票:"+tickets);
tickets -= 1;
}
}
} public class ThreadTest
{
public static void main(String[] args)
{
RunnableDemo r = new RunnableDemo();
new Thread(r).start();
new Thread(r).start();
new Thread(r).start();
new Thread(r).start();
}
}
二、死锁
如果有一组进程(或线程),线程1 已经占据资源R1,并持有资源R1上的锁,而且正在等待资源R2开锁;线程2已经占据资源R2,并拥有资源R2上的锁,却正在等待R1开锁。那么这两个线程都不释放自己占据的资源,同时申请不到对方资源上的锁,它们只能永远等待下去。这种现象就叫做死锁。
预防死锁的一种方法:利用有序资源分配策略——要求线程申请资源必须按照以编号上升的次序依次申请。
三、线程间通信
同属于一个进程的多个线程,是共享地址空间的,它们可以相互通信,共同协作来完成指定任务。
Java是通过Object类的wait()、notify()、notifyAll()这几个方法来实现线程间的通信。
wait():线程进入睡眠状态,直到其他线程进入并调用notify()或notifyAll()为止。
notify():唤醒在该同步代码块中第1个调用wait()的线程。
notifyAll():唤醒在该同步代码块中所有调用wait()的线程,高优先级最先被唤醒。
class Producer implements Runnable
{
Person q = null;
public Producer(Person q)
{
this.q=q;
}
@Override
public void run()
{
for(int i=0;i<10;i++)
{
if(i%2==0)
{
q.set("张三","男");
}
else{
q.set("李四","女");
}
}
}
}
class Consumer implements Runnable
{
Person q = null;
public Consumer(Person q)
{
this.q=q;
}
@Override
public void run()
{
for(int i=0;i<10;++i)
{
q.get();
}
}
}
class Person
{
private String name = "李四";
private String sex = "女";
private boolean bFull = false;//当Consumer线程取走数据后,false
public synchronized void set(String name,String sex)
{
if(bFull)
{
try
{
wait();//后来的线程要等待
}catch(InterruptedException e){
e.printStackTrace();
}
}
this.name = name;
this.sex = sex;
bFull = true;//当Producer线程放入数据后,true
notify();//唤醒最先到达的线程
}
public synchronized void get()
{
if(!bFull)
{
try{
wait();
}catch(InterruptedException e){
e.printStackTrace();
}
}
System.out.println(name+"——>"+sex);
bFull = false;
notify();
}
}
public class ThreadCommunation
{
public static void main(String[] args)
{
Person q = new Person();
new Thread(new Producer(q)).start();
new Thread(new Consumer(q)).start();
}
}
***注意:wait()、notify()、notifyAll()这三个方法必须在synchronized方法中调用,该线程必须得到该对象的所有权。
四、线程的生命周期
控制线程生命周期的方法:suspend()、resume()、stop()方法,但是这三个方法都不推荐使用。
若想控制线程的生命周期,推荐使用在run()方法中添加循环条件的方法来实现对线程生命周期的控制。
线程同步、死锁和通信——Java多线程(二)的更多相关文章
- 多线程,线程类三种方式,线程调度,线程同步,死锁,线程间的通信,阻塞队列,wait和sleep区别?
重难点梳理 知识点梳理 学习目标 1.能够知道什么是进程什么是线程(进程和线程的概述,多进程和多线程的意义) 2.能够掌握线程常见API的使用 3.能够理解什么是线程安全问题 4.能够知道什么是锁 5 ...
- java 多线程二
java 多线程一 java 多线程二 java 多线程三 java 多线程四 线程中断: /** * Created by root on 17-9-30. */ public class Test ...
- java多线程(二)
线程的阻塞状态: 参考java多线程(一)多线程的生命周期图解,多线程的五种状态. 1.1 join(),如果在A线程体里面执行了B线程的join()方法,那么A线程阻塞,直到B线程生命周期结 ...
- java多线程二之线程同步的三种方法
java多线程的难点是在:处理多个线程同步与并发运行时线程间的通信问题.java在处理线程同步时,常用方法有: 1.synchronized关键字. 2.Lock显示加锁. 3.信号量Se ...
- Java多线程(二) 多线程的锁机制
当两条线程同时访问一个类的时候,可能会带来一些问题.并发线程重入可能会带来内存泄漏.程序不可控等等.不管是线程间的通讯还是线程共享数据都需要使用Java的锁机制控制并发代码产生的问题.本篇总结主要著名 ...
- java多线程(八)-死锁问题和java多线程总结
为了防止对共享受限资源的争夺,我们可以通过synchronized等方式来加锁,这个时候该线程就处于阻塞状态,设想这样一种情况,线程A等着线程B完成后才能执行,而线程B又等着线程C,而线程C又等着线程 ...
- Java多线程(二) —— 深入剖析ThreadLocal
对Java多线程中的ThreadLocal类还不是很了解,所以在此总结一下. 主要参考了http://www.cnblogs.com/dolphin0520/p/3920407.html 中的文章. ...
- 从零开始学习Java多线程(二)
前面已经简单介绍进程和线程,为后续学习做铺垫.本文讨论多线程传参,Java多线程异常处理机制. 1. 多线程的参数传递 在传统开发过程中,我们习惯在调用函数时,将所需的参数传入其中,通过函数内部逻辑处 ...
- 经典线程同步问题(生产者&消费者)--Java实现
生产者-消费者(producer-consumer)问题是一个著名的线程同步问题.它描述的是:有一群生产者线程在生产产品,并将这些产品提供给消费者线程去消费. 为使生产者与消费者之间能够并发执行,在两 ...
随机推荐
- [转]RDLC报表——动态添加列
本文转自:http://www.cnblogs.com/pszw/archive/2012/07/19/2599937.html 前言 最近接到一个需求:在给定的数据源中,某(些)列,可能需要单独统计 ...
- D - Garden
Problem description Luba thinks about watering her garden. The garden can be represented as a segmen ...
- Android 在线升级
1.获取当前安装版本 //获取当前版本 public int getVersion(Context context){ ; try { version = context.getPackageMana ...
- Deutsch lernen (13)
1. die Sicherheit, -en 安全(性) Was ist Ihnen wichtiger: Freiheit oder Sicherheit? Wie ist es mit der ...
- MatLab之Simulink之simple model
Use Simulink to model a system and then simulate the dynamic behavior of that system. 1 Open in Comm ...
- Java_Web之JSTL和EL
今天学了JSTL和EL,替换了以前for循环,感觉代码越来越少了,十分方便.JSTL和EL密不可分. 一.什么是EL表达式? 什么是EL EL即Expression Language(表达式语言) E ...
- 如何在编辑器打开Java程序
我们都知道运行JAVA文件,可以从软件控制台运行我们写好的java文件,也可以从windows窗口运行,我们最开始接触的是通过windows窗口来运行java文件,下面简单介绍一下如何如何在编辑器打开 ...
- JavaOO知识点小结一
Java语言的特点是什么?简单 面向对象 跨平台 多线程 健壮性安全性 垃圾回收机制如何编译和执行java文件?产生帮助文档用什么命令?编译: javac 文件名执行: java 类名产生帮助文档 j ...
- c#动态类型Dynamic
需引用System.Dynamic命名空间 来源:http://www.cnblogs.com/ryanding/archive/2010/12/09/1900106.html dynamic Cus ...
- java操作Excel的poi 创建一个sheet页
package com.java.poi; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.us ...