线程同步、死锁和通信——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)问题是一个著名的线程同步问题.它描述的是:有一群生产者线程在生产产品,并将这些产品提供给消费者线程去消费. 为使生产者与消费者之间能够并发执行,在两 ...
随机推荐
- CAS配置记录
CAS配置(1)之证书配置 CAS配置(2)之主配置 CAS配置(3)之restful-api接入接口
- NPOI导出Excel自动计算公式问题
以前用过sheet.ForceFormulaRecalculation = true;当时能够自动计算出来. 今天把模板改了一下(没动公式,但是模板是老板改的,我也不知道他操作了什么),结果就不能自动 ...
- matplotlib之pyplot 知识点滴
以下是一些常用地址链接,请参考 matplotlib 官方网址 plt.plot()函数细节 Matplotlib 中文用户指南 4.6 编写数学表达式 Python seaborn matplotl ...
- Beta冲刺-星期四
这个作业属于哪个课程 <课程的链接> 这个作业要求在哪里 <作业要求的链接> 团队名称 Three cobblers 这个作业的目标 完成今天的冲刺 一 ...
- 如何通过WallpaperManager(壁纸管理器)设置与修改壁纸?
WallpaperManager(壁纸管理器),是手机壁纸相关的一个API的相关类.其设置壁纸常有如下三种方法可调用: - setBitmap(Bitmap bitmap):将壁纸设置为bitmap所 ...
- easyui combobox的增加全选解决方案
1.解决方案背景: 项目中偶然需要用到easyui的combobox的组件,但是本组件自己没有包含全选的api事件.搜索了一些解决方案,但是不是很符合,后来发现是因为所使用的版本不一致所导致的.项 ...
- MyEclipse加入jquery.js文件missing semicolon的错误
今天打开项目,发现有一个小红叉,虽然不影响项目的编译和运行,但是看着非常影响心情.原因是jquery-1.8.2.min.js报了一堆missing semicolon的错误.之所以会这样,其实是My ...
- Visual Studio UI Automation 学习(一)
这几天需要研究自动化测试工具,因为团队开发使用visual studio,所以需要研究一下Visual studio自带的框架. 刚开始安装的时候,没有选自定义安装,所以安装完成后没有找到UI Aut ...
- 11.03 在外链接中用OR逻辑
select e.ename,d.deptno,d.dname,d.locfrom dept d left join emp e on(d.deptno = e.deptnoand (e.deptno ...
- efcore 控制台迁移架构
添加 nuget 包: Microsoft.EntityFrameworkCore.Design Microsoft.EntityFrameworkCore.SqlServer Microsoft.E ...