一、多线程同步

上一篇随笔中,我曾遇到对多线程程序的多次运行结果不一致的情况,这主要是因为没有对这些线程在访问临界资源做必要的控制,而接下来就用线程的同步来解决这个问题。

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多线程(二)的更多相关文章

  1. 多线程,线程类三种方式,线程调度,线程同步,死锁,线程间的通信,阻塞队列,wait和sleep区别?

    重难点梳理 知识点梳理 学习目标 1.能够知道什么是进程什么是线程(进程和线程的概述,多进程和多线程的意义) 2.能够掌握线程常见API的使用 3.能够理解什么是线程安全问题 4.能够知道什么是锁 5 ...

  2. java 多线程二

    java 多线程一 java 多线程二 java 多线程三 java 多线程四 线程中断: /** * Created by root on 17-9-30. */ public class Test ...

  3. java多线程(二)

    线程的阻塞状态: 参考java多线程(一)多线程的生命周期图解,多线程的五种状态.     1.1 join(),如果在A线程体里面执行了B线程的join()方法,那么A线程阻塞,直到B线程生命周期结 ...

  4. java多线程二之线程同步的三种方法

          java多线程的难点是在:处理多个线程同步与并发运行时线程间的通信问题.java在处理线程同步时,常用方法有: 1.synchronized关键字. 2.Lock显示加锁. 3.信号量Se ...

  5. Java多线程(二) 多线程的锁机制

    当两条线程同时访问一个类的时候,可能会带来一些问题.并发线程重入可能会带来内存泄漏.程序不可控等等.不管是线程间的通讯还是线程共享数据都需要使用Java的锁机制控制并发代码产生的问题.本篇总结主要著名 ...

  6. java多线程(八)-死锁问题和java多线程总结

    为了防止对共享受限资源的争夺,我们可以通过synchronized等方式来加锁,这个时候该线程就处于阻塞状态,设想这样一种情况,线程A等着线程B完成后才能执行,而线程B又等着线程C,而线程C又等着线程 ...

  7. Java多线程(二) —— 深入剖析ThreadLocal

    对Java多线程中的ThreadLocal类还不是很了解,所以在此总结一下. 主要参考了http://www.cnblogs.com/dolphin0520/p/3920407.html 中的文章. ...

  8. 从零开始学习Java多线程(二)

    前面已经简单介绍进程和线程,为后续学习做铺垫.本文讨论多线程传参,Java多线程异常处理机制. 1. 多线程的参数传递 在传统开发过程中,我们习惯在调用函数时,将所需的参数传入其中,通过函数内部逻辑处 ...

  9. 经典线程同步问题(生产者&消费者)--Java实现

    生产者-消费者(producer-consumer)问题是一个著名的线程同步问题.它描述的是:有一群生产者线程在生产产品,并将这些产品提供给消费者线程去消费. 为使生产者与消费者之间能够并发执行,在两 ...

随机推荐

  1. Run as ant build每次都执行两次

    因为用了selenium+testng+ant的框架,所以每次执行自动化,我就run as ant build.发现测试每次都执行两次,很奇怪.因为也没有影响到测试结果,所以一开始也就let it g ...

  2. 【Leetcode】376. Wiggle Subsequence

    Description: A sequence of numbers is called a wiggle sequence if the differences between successive ...

  3. java 微信api开发

    最近使用了一个很好的微信api框架,比较好使. 源码地址:https://github.com/chanjarster/weixin-java-tools/wiki 微信公众平台:微信公众平台开发文档 ...

  4. POI合并单元边框问题解决方法

    http://blog.csdn.net/hardworking0323/article/details/51105430

  5. 自学Python七 爬虫实战一

    此文承接上文,让我们写一个简简单单的爬虫,循序而渐进不是吗?此次进行的练习是爬取前5页什么值得买网站中的白菜价包邮信息.包括名称,价格,推荐人,时间. 我们所需要做的工作:1.确定URL并获得页面代码 ...

  6. 关于MYSQL 存储过程的文章摘录

    1.      存储过程简介   我们常用的操作数据库语言SQL语句在执行的时候需要要先编译,然后执行,而存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,经编译后存储 ...

  7. MyEclipse获取注册码

    最近刚装上MyEclipse,一直弹窗提示注册码过期,开始还能接受,到最后,每发布一个项目便弹窗提醒,顿时感觉烦了,得治理治理这个烦人的注册码,下面是一段自动生成注册名和注册码的代码,只需要直接拿来用 ...

  8. 【sqli-labs】 less26a GET- Blind based -All you SPACES and COMMENTS belong to us -String-single quotes-Parenthesis(GET型基于盲注的去除了空格和注释的单引号括号注入)

    这个和less26差不多,空格还是用%a0代替,26过了这个也就简单了 ;%00 可以代替注释,尝试一下 order by 3 http://192.168.136.128/sqli-labs-mas ...

  9. jq 禁用复选框 和输入框

    $('input').attr("readonly", ""); $('input').attr("disabled", "fal ...

  10. bos开发时,测试卡在登录界面解决

    在BOS工作空间工程路径下新建sp文件夹,如在E:\bosworkspace8.2\Project_0\lib 新建sp文件夹E:\bosworkspace8.2\Project_0\lib\sp.然 ...