`
cainiaoyu
  • 浏览: 22006 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Java多线程通信

阅读更多
上一篇介绍Java提供synchronized关键字来实现多线程同步。如下例所示:
代码:
class ThreadA implements Runnable {
private Parcel7 p;

public ThreadA(Parcel7 p) {

this.p = p;

}

public void run() {

while (true) {

p.input();

}

}

}

class ThreadB implements Runnable {

private Parcel7 p;

public ThreadB(Parcel7 p) {

this.p = p;

}

public void run() {

while (true) {

p.output();

}

}

}

public class Parcel7 {

private int count = 0;

synchronized void input() {

count ++;

System.out.println(Thread.currentThread().getName() + "+++  " + count);

}

synchronized void output() {

count --;

System.out.println(Thread.currentThread().getName() + "---  " + count);

}

public static void main(String[] args) {

Parcel7 test = new Parcel7();

ThreadA a = new ThreadA(test);

ThreadB b = new ThreadB(test);

new Thread(a).start();

new Thread(b).start();

}

}
使用了两个synchronized 方法来使的对count的操作对于线程a和b是一个互斥的过程。但是如果我们我们想要使得a,b线程交替执行的话,我们需要使用到多线程之间的通信方式:wait(),notify(),notifyAll()。这三个方法是属于java.lang.Object类中的,即所有对象都包含这三个方法。wait()是使当前线程放弃CPU执行权限,并等待(会抛出一个 InterruptedException的异常)。void notify()和void notifyAll()用来唤醒持有该对象锁线程,前者唤醒单个,后者唤醒所有。当然,这三者所操作的都是持有对象锁的线程,所以需要跟synchronized一起使用。
代码:

class ThreadA implements Runnable {

private Parcel7 p;

public ThreadA(Parcel7 p) {

this.p = p;

}

public void run() {

while (true) {

p.input();

}

}

}

class ThreadB implements Runnable {

private Parcel7 p;

public ThreadB(Parcel7 p) {

this.p = p;

}

public void run() {

while (true) {

p.output();

}

}

}

public class Parcel7 {

private int count = 0;

private boolean flag = false;

synchronized void input() {

while (flag) {

try {

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

count ++;

System.out.println(Thread.currentThread().getName() + "+++  " + count);

flag = true;

this.notify();

}

synchronized void output() {

while (!flag) {

try {

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

count --;

System.out.println(Thread.currentThread().getName() + "---  " + count);

flag = false;

this.notify();

}

public static void main(String[] args) {

Parcel7 test = new Parcel7();

ThreadA a = new ThreadA(test);

ThreadB b = new ThreadB(test);

new Thread(a).start();

new Thread(b).start();
                // new Thread(a).start();
                // new Thread(b).start();

}

}
可以正确使线程a,b交替执行,因为每次a执行完一次之后都会,把b唤醒并自己进入wait状态,b被唤醒后做a同样的操作。但当每个任务都不止一个线程操作时,(把上例的注释部分去掉)会出现如下情况:
【运行结果】

Thread-3---  0

Thread-0+++  1

Thread-1---  0

Thread-0+++  1
Thread-3---  0
没有无限执行而是停住了。因为四个线程都陷入wait状态了。
解决办法:
将notify改成notifyAll,每次都把所有wait中的线程唤醒,主要是为了确保把执行不同操作的线程唤醒。而不是唤醒执行相同操作的线程。问题:使用notifyAll不仅把对方线程唤醒,还把本方线程也都唤醒了。如何只唤醒本方线程。
java5.0之前只能通过synchronized提供锁机制,而java5.0之后提供了一个接口:Lock里面包含了lock()获取锁的方法,和unlock()主动解锁的方法。并且将对象锁封装成一个接口Condition,通过Condition的实例对象来取代原本的对象锁。
代码:

import java.util.concurrent.locks.Condition;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

class ThreadA implements Runnable {

private Parcel7 p;

public ThreadA(Parcel7 p) {

this.p = p;

}

public void run() {

while (true) {

p.input();

}

}

}

class ThreadB implements Runnable {

private Parcel7 p;

public ThreadB(Parcel7 p) {

this.p = p;

}

public void run() {

while (true) {

p.output();

}

}

}

public class Parcel7 {

private int count = 0;

private boolean flag = false;

Lock lock = new ReentrantLock();

Condition condition = lock.newCondition();

Condition condition2 = lock.newCondition();

void input() {

lock.lock();

try{

while (flag) {

try {

condition.await();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

count ++;

System.out.println(Thread.currentThread().getName() + "+++  " + count);

flag = true;

condition2.signal();

}finally{

lock.unlock();

}

}

void output() {

lock.lock();

try{

while (!flag) {

try {

condition2.await();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

count --;

System.out.println(Thread.currentThread().getName() + "---  " + count);

flag = false;

condition.signal();

}finally{

lock.unlock();

}

}

public static void main(String[] args) {

Parcel7 test = new Parcel7();

ThreadA a = new ThreadA(test);

ThreadB b = new ThreadB(test);

new Thread(a).start();

new Thread(a).start();

new Thread(b).start();

new Thread(b).start();

}

}
对于synchronized每次只能持有一把锁,而对于Lock可以通过newCondition方法来获取好几个不同的对象锁。
总结:
synchronized与lock的区别:
1,ReentrantLock 拥有Synchronized相同的并发性和内存语义,此外还多了 锁投票,定时锁等候和中断锁等候
     线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定,

     如果使用 synchronized ,如果A不释放,B将一直等下去,不能被中断

     如果 使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事
2,synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动  释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中
3,在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态;
停止线程:interrupt(),java.lang.Thread中的一个方法,用于将wait()、join()、sleep的线程中断状态清除并返回一个InterruptedException。
代码:

class ThreadA implements Runnable {

public synchronized void run() {

try {

this.wait();

} catch (InterruptedException e) {

System.out.println("从中断中恢复!");

}

}

}

public class Parcel7 {

public static void main(String[] args) {

ThreadA a = new ThreadA();

Thread b= new Thread(a);

b.start();

b.interrupt();

}

}
【运行结果】
从中断中恢复!
守护线程:是为其他线程的运行提供便利的线程。守护线程不会阻止程序的终止。Java的垃圾收集机制的某些实现就使用了守护线程。
非守护线程:包括常规的用户线程或诸如用于处理GUI事件的事件调度线程。
java.lang.Thread中的一个方法setDaemon(),用于将某线程设置为守护线程,必须在调用它的start方法之前进行设置,否则,抛出IllegalThreadStateException异常。程序只有守护线程时,该程序便可以结束运行。
代码:
class ThreadA implements Runnable {

public  void run() {

while (true) {

System.out.println(Thread.currentThread().getName()+"守护线程!");

}

}

}

public class Parcel7 {

public static void main(String[] args) {

ThreadA a = new ThreadA();

Thread b= new Thread(a);

Thread c= new Thread(a);

b.setDaemon(true);

c.setDaemon(true);

b.start();

c.start();

}

}

当主线程结束时,两个守护线程也同时结束,虽然执行时while(true)的无限循环;
等待线程结束:java.lang.Thread中的方法join();如果被interrupt()中断时抛出InterruptedException。也可以用来实现线程之间的同步。

代码:

class ThreadA implements Runnable {

private Parcel7 p;

public ThreadA(Parcel7 p) {

this.p = p;

}

public void run() {

for (int i = 0; i < 10; i++) {

p.inc();

}

}

}

public class Parcel7 {

private static int a =0;

void inc(){

a++;

}

public static void main(String[] args) {

ThreadA A = new ThreadA(new Parcel7());

Thread b= new Thread(A);

b.start();

System.out.println(a);

try {

b.join();

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(a);

}

}
【输出结果】
0

10
释放cpu执行权:yield()。该方法与sleep()类似,只是不能由用户指定暂停多长时间,并且yield()方法只能让同优先级的线程有执行的机会。而sleep()可以使低优先级的线程得到执行的机会,当然也可以让同优先级、高优先级的线程有执行的机会。sleep和yield都不会释放对象锁。

        实际上,yield()方法对应了如下操作;先检测当前是否有相同优先级的线程处于同可运行状态,如有,则把CPU的占有权交给次线程,否则继续运行原来的线程,所以yield()方法称为“退让”,它把运行机会让给了同等级的其他线程。
        sleep 方法允许较低优先级的线程获得运行机会,但yield()方法执行时,当前线程仍处在可运行状态,所以不可能让出较低优先级的线程此时获取CPU占有权。在一个运行系统中,如果较高优先级的线程没有调用sleep方法,也没有受到I/O阻塞,那么较低优先级线程只能等待所有较高优先级的线程运行结束,方可有机会运行。
分享到:
评论

相关推荐

    java多线程通信图解

    一张图方便理解和掌握java 多线程之间通信的实质 java 多线程 其实就是每个线程都拥有自己的内存空间,多线程之间的通信,比例A线程修改了主内存(main方法的线程)变量,需要把A线程修改的结果同步到主线程中,...

    Java多线程通信机制研究.pdf

    "Java多线程通信机制研究" Java多线程通信机制是Java程序设计中的一个复杂技术,涉及到多个线程之间的通信和协作。多线程是一种程序运行机制,它允许在程序中并发执行多个指令流,每个指令流都被称为一个线程,彼此...

    JAVA多线程通信学习_服务器多线程通信_

    总的来说,Java多线程通信是一个复杂而重要的主题,涉及并发控制、线程安全、同步机制等多个方面。通过深入理解并熟练运用这些知识,开发者可以构建出高效、可靠的服务器多线程应用程序。在实际操作中,不断实践和...

    Java多线程通信服务端程序例子

    一个多线程通信服务端程序的简单例子,可以根据情况增加业务逻辑。

    多线程通信ThreadDemo

    在Java编程中,多线程通信是一个重要的概念,特别是在并发编程中。`ThreadDemo`示例可能演示了...通过分析和学习这个示例,开发者可以更好地理解和掌握Java多线程通信的实践技巧,从而编写出更加高效、可靠的并发程序。

    java多线程经典案例

    本案例将深入探讨Java多线程中的关键知识点,包括线程同步、线程通信和线程阻塞。 线程同步是为了防止多个线程同时访问共享资源,导致数据不一致。Java提供了多种同步机制,如synchronized关键字、Lock接口...

    Java多线程通信实现方式详解

    Java多线程通信实现方式详解 Java多线程通信是指在多线程编程中,线程之间的通信和同步机制。多线程通信的目的是为了让不同的线程之间能够共享数据和资源,实现线程之间的协作和同步。Java中提供了多种多线程通信...

    Java多线程知识点总结

    Java多线程是Java编程语言中一个非常重要的概念,它允许开发者在一个程序中创建多个执行线程并行运行,以提高程序的执行效率和响应速度。在Java中,线程的生命周期包含五个基本状态,分别是新建状态(New)、就绪...

    java tcp多线程通信

    Java TCP多线程通信是网络编程中的一个重要概念,它结合了Java的Socket编程与多线程技术,使得多个客户端能够同时与服务器进行交互。在Java中,TCP(传输控制协议)提供了一种可靠的数据传输方式,确保数据的有序、...

    java多线程的讲解和实战

    Java多线程是Java编程中的重要概念,尤其在如今的多核处理器环境下,理解并熟练掌握多线程技术对于提高程序性能和响应速度至关重要。本资料详细讲解了Java多线程的原理,并提供了丰富的实战代码,非常适合Java初学者...

    Java多线程通信:交替打印ABAB实例

    Java多线程通信是并发编程中的重要概念,它允许不同线程之间进行协作,以便在共享资源时有序地执行任务。在这个场景下,我们关注的是如何实现两个线程交替打印"A"和"B",形成"ABABAB"这样的序列。 在给出的示例中,...

    Java多线程通信wait()和notify()代码实例

    "Java多线程通信wait()和notify()代码实例" Java多线程通信是Java编程语言中一个重要的概念,它允许程序同时执行多个线程,以提高程序的效率和响应速度。在Java中,多线程通信主要通过wait()和notify()方法实现,...

    java多线程Demo

    Java多线程是Java编程中的一个重要概念,它允许程序同时执行多个任务,提高了程序的效率和响应速度。在Java中,实现多线程有两种主要方式:继承Thread类和实现Runnable接口。 1. 继承Thread类: 当我们创建一个新...

    深入浅出 Java 多线程.pdf

    在本文中,我们将深入浅出Java多线程编程的世界,探索多线程编程的基本概念、多线程编程的优点、多线程编程的缺点、多线程编程的应用场景、多线程编程的实现方法等内容。 一、多线程编程的基本概念 多线程编程是指...

    汪文君JAVA多线程编程实战(完整不加密)

    Java多线程允许程序同时执行多个独立的代码段,这在处理大数据、网络通信、用户界面更新等场景中尤其有用。书中详细介绍了Java多线程的核心概念,如线程的创建、启动、同步、协作以及生命周期管理。读者将学习如何...

    JAVA多线程编程技术PDF

    总结起来,“JAVA多线程编程技术PDF”涵盖了多线程的基本概念、同步机制、线程通信、死锁避免、线程池以及线程安全的集合类等内容。通过深入学习这份资料,开发者可以全面掌握Java多线程编程技术,提升程序的并发...

    java 多线程并发实例

    在Java编程中,多线程并发是提升程序执行效率、充分利用多核处理器资源的重要手段。本文将基于"java 多线程并发实例"这个主题,深入探讨Java中的多线程并发概念及其应用。 首先,我们要了解Java中的线程。线程是...

    JAVAJAVA多线程教学演示系统论文

    《JAVA多线程教学演示系统》是一篇深入探讨JAVA多线程编程的论文,它针对教育领域中的教学需求,提供了一种生动、直观的演示方式,帮助学生更好地理解和掌握多线程技术。这篇论文的核心内容可能包括以下几个方面: ...

    Java多线程编程核心技术_完整版_java_

    Java多线程编程是Java开发中的重要组成部分,它允许程序同时执行多个任务,极大地提高了程序的效率和响应性。在Java中,多线程主要通过继承Thread类或实现Runnable接口来实现。本教程《Java多线程编程核心技术》将...

    Java 线程通信示例 源代码

    在Java编程中,多线程通信是一个至关重要的概念,特别是在设计高效的并发应用程序时。这个"Java线程通信示例源代码"很可能包含了演示如何在不同线程之间共享数据和协调执行顺序的实例。线程通信主要涉及两个核心概念...

Global site tag (gtag.js) - Google Analytics