java进程间通信:
来源:互联网 发布:网络泄露个人隐私 编辑:程序博客网 时间:2024/05/22 03:18
java进程间通信:
(一)通信的方法:
线程之间需要一些协调通信,来共同完成一件任务。
Object类中相关的方法有两个notify方法和三个wait方法。
(wait和notify方法定义在Object类中,因此会被所有的类所继承。
这些方法都是final的,即它们都是不能被重写的,不能通过子类覆写去改变它们的行为。)
(二)wait方法:
当前的线程必须拥有当前对象的monitor,也即lock,就是锁。
wait()方法,释放锁,然后等待另外的线程来通知它(通知的方式是notify()或者notifyAll()方法)。
确保调用wait()方法的时候拥有锁,即,wait()方法的调用必须放在synchronized方法或synchronized块中。
2)区分wait与sleep:
Thread.sleep(),它会导致线程睡眠指定的毫秒数,但线程在睡眠的过程中是不会释放掉对象的锁的。
(2)notify():唤醒一个等待当前对象的锁的线程。
被唤醒的线程是不能被执行的,需要等到当前线程放弃这个对象的锁。notify方法调用必须放在synchronized方法或synchronized块中,因为notify()方法应该是被拥有对象的锁的线程所调用。。
(3)总结:
1)wait()和notify()方法要求在调用时线程已经获得了对象的锁,因此对这两个方法的调用需要放在synchronized方法或synchronized块中。
2)一个线程变为一个对象的锁的拥有者是通过下列三种方法:
1.执行这个对象的synchronized实例方法。
2.执行这个对象的synchronized语句块。这个语句块锁的是这个对象。
3.对于Class类的对象,执行那个类的synchronized、static方法。
(三)范例:
(1)问题:
利用两个线程,对一个整形成员变量进行变化,一个对其增加,一个对其减少,利用线程间的通信,实现该整形变量0101这样交替的变更。
(2)方法一:
public class NumberHolder
{
private int number;
public synchronized void increase()//打印1
{
if (0 != number)
{
try
{
wait();//如果1已经打印了,则打印1的进程等待。应该打印0的进程。
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
// 能执行到这里说明已经被唤醒
// 并且number为0
number++;
System.out.println(number);
notify();//1打印完了之后,通知打印0的进程。
}
public synchronized void decrease()//打印0
{
if (0 == number)
{
try
{
wait();//如果前一个打印的是0,则打印0的等待。
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
// 能执行到这里说明已经被唤醒
// 并且number不为0
number--;
System.out.println(number);
notify();//通知打印1的。
}
}
public class IncreaseThread extends Thread
{
private NumberHolder numberHolder;
public IncreaseThread(NumberHolder numberHolder)
{
this.numberHolder = numberHolder;
}
@Override
public void run()
{
for (int i = 0; i < 20; ++i)
{
// 进行一定的延时
try
{
Thread.sleep((long) Math.random() * 1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
// 进行增加操作
numberHolder.increase();
}
}
}
public class DecreaseThread extends Thread
{
private NumberHolder numberHolder;
public DecreaseThread(NumberHolder numberHolder)
{
this.numberHolder = numberHolder;
}
@Override
public void run()
{
for (int i = 0; i < 20; ++i)
{
// 进行一定的延时
try
{
Thread.sleep((long) Math.random() * 1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
// 进行减少操作
numberHolder.decrease();
}
}
}
public class NumberTest
{
public static void main(String[] args)
{
NumberHolder numberHolder = new NumberHolder();
Thread t1 = new IncreaseThread(numberHolder);
Thread t2 = new DecreaseThread(numberHolder);
//打印1和打印0是对同一个对象资源的竞争,实现了同步。
t1.start();
t2.start();
}
}
-------------
(3)扩展:
如果再多加上两个线程呢?
即把其中的NumberTest类改为如下:
public class NumberTest
{
public static void main(String[] args)
{
NumberHolder numberHolder = new NumberHolder();
Thread t1 = new IncreaseThread(numberHolder);
Thread t2 = new DecreaseThread(numberHolder);
Thread t3 = new IncreaseThread(numberHolder);
Thread t4 = new DecreaseThread(numberHolder);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
结果错误;
分析:
1)因为线程在wait()的时候,接收到其他线程的通知,即往下执行,不再进行判断。
2)两个线程的情况下,唤醒的肯定是另一个线程。
3)但是在多个线程的情况下,执行结果就会混乱无序。比如,一个可能的情况是,一个增加线程执行的时候,其他三个线程都在wait,这时候第一个线程调用了notify()方法,其他线程都将被唤醒,然后执行各自的增加或减少方法。
4)解决方法:
在被唤醒之后仍然进行条件判断,去检查要改的数字是否满足条件,如果不满足条件就继续睡眠。把两个方法中的if改为while即可。
public class NumberHolder
{
private int number;
public synchronized void increase()
{
while (0 != number)
{
try
{
wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
// 能执行到这里说明已经被唤醒
// 并且number为0
number++;
System.out.println(number);
// 通知在等待的线程
notify();
}
public synchronized void decrease()
{
while (0 == number)
{
try
{
wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
// 能执行到这里说明已经被唤醒
// 并且number不为0
number--;
System.out.println(number);
notify();
}
}
(一)通信的方法:
线程之间需要一些协调通信,来共同完成一件任务。
Object类中相关的方法有两个notify方法和三个wait方法。
(wait和notify方法定义在Object类中,因此会被所有的类所继承。
这些方法都是final的,即它们都是不能被重写的,不能通过子类覆写去改变它们的行为。)
(二)wait方法:
当前的线程必须拥有当前对象的monitor,也即lock,就是锁。
wait()方法,释放锁,然后等待另外的线程来通知它(通知的方式是notify()或者notifyAll()方法)。
确保调用wait()方法的时候拥有锁,即,wait()方法的调用必须放在synchronized方法或synchronized块中。
2)区分wait与sleep:
Thread.sleep(),它会导致线程睡眠指定的毫秒数,但线程在睡眠的过程中是不会释放掉对象的锁的。
(2)notify():唤醒一个等待当前对象的锁的线程。
被唤醒的线程是不能被执行的,需要等到当前线程放弃这个对象的锁。notify方法调用必须放在synchronized方法或synchronized块中,因为notify()方法应该是被拥有对象的锁的线程所调用。。
(3)总结:
1)wait()和notify()方法要求在调用时线程已经获得了对象的锁,因此对这两个方法的调用需要放在synchronized方法或synchronized块中。
2)一个线程变为一个对象的锁的拥有者是通过下列三种方法:
1.执行这个对象的synchronized实例方法。
2.执行这个对象的synchronized语句块。这个语句块锁的是这个对象。
3.对于Class类的对象,执行那个类的synchronized、static方法。
(三)范例:
(1)问题:
利用两个线程,对一个整形成员变量进行变化,一个对其增加,一个对其减少,利用线程间的通信,实现该整形变量0101这样交替的变更。
(2)方法一:
public class NumberHolder
{
private int number;
public synchronized void increase()//打印1
{
if (0 != number)
{
try
{
wait();//如果1已经打印了,则打印1的进程等待。应该打印0的进程。
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
// 能执行到这里说明已经被唤醒
// 并且number为0
number++;
System.out.println(number);
notify();//1打印完了之后,通知打印0的进程。
}
public synchronized void decrease()//打印0
{
if (0 == number)
{
try
{
wait();//如果前一个打印的是0,则打印0的等待。
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
// 能执行到这里说明已经被唤醒
// 并且number不为0
number--;
System.out.println(number);
notify();//通知打印1的。
}
}
public class IncreaseThread extends Thread
{
private NumberHolder numberHolder;
public IncreaseThread(NumberHolder numberHolder)
{
this.numberHolder = numberHolder;
}
@Override
public void run()
{
for (int i = 0; i < 20; ++i)
{
// 进行一定的延时
try
{
Thread.sleep((long) Math.random() * 1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
// 进行增加操作
numberHolder.increase();
}
}
}
public class DecreaseThread extends Thread
{
private NumberHolder numberHolder;
public DecreaseThread(NumberHolder numberHolder)
{
this.numberHolder = numberHolder;
}
@Override
public void run()
{
for (int i = 0; i < 20; ++i)
{
// 进行一定的延时
try
{
Thread.sleep((long) Math.random() * 1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
// 进行减少操作
numberHolder.decrease();
}
}
}
public class NumberTest
{
public static void main(String[] args)
{
NumberHolder numberHolder = new NumberHolder();
Thread t1 = new IncreaseThread(numberHolder);
Thread t2 = new DecreaseThread(numberHolder);
//打印1和打印0是对同一个对象资源的竞争,实现了同步。
t1.start();
t2.start();
}
}
-------------
(3)扩展:
如果再多加上两个线程呢?
即把其中的NumberTest类改为如下:
public class NumberTest
{
public static void main(String[] args)
{
NumberHolder numberHolder = new NumberHolder();
Thread t1 = new IncreaseThread(numberHolder);
Thread t2 = new DecreaseThread(numberHolder);
Thread t3 = new IncreaseThread(numberHolder);
Thread t4 = new DecreaseThread(numberHolder);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
结果错误;
分析:
1)因为线程在wait()的时候,接收到其他线程的通知,即往下执行,不再进行判断。
2)两个线程的情况下,唤醒的肯定是另一个线程。
3)但是在多个线程的情况下,执行结果就会混乱无序。比如,一个可能的情况是,一个增加线程执行的时候,其他三个线程都在wait,这时候第一个线程调用了notify()方法,其他线程都将被唤醒,然后执行各自的增加或减少方法。
4)解决方法:
在被唤醒之后仍然进行条件判断,去检查要改的数字是否满足条件,如果不满足条件就继续睡眠。把两个方法中的if改为while即可。
public class NumberHolder
{
private int number;
public synchronized void increase()
{
while (0 != number)
{
try
{
wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
// 能执行到这里说明已经被唤醒
// 并且number为0
number++;
System.out.println(number);
// 通知在等待的线程
notify();
}
public synchronized void decrease()
{
while (0 == number)
{
try
{
wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
// 能执行到这里说明已经被唤醒
// 并且number不为0
number--;
System.out.println(number);
notify();
}
}
0 0
- java进程间通信
- java进程间通信:
- java进程间通信
- Java进程间通信
- 【转】Java进程间通信
- java 进程间的通信
- java进程间通信junixsocket
- Java NIO 进程间通信
- java进程间通信方式
- 进程&进程间通信
- java中进程间的通信
- JAVA线程与进程间的通信
- java进程间通信(IPC interProcess communication)
- Java通过管道进行进程间通信
- Java进程间通信的方法
- java如何实现进程间的通信?
- Java 进程通信
- java 进程通信方式
- 【Java】【SSH】Web 开发经典框架Spring+Struts+Hibernate官方网站下载地址
- Team Foundation Server BuilderService LOG
- java基础知识复习总结--增强型for循环
- 随想录(提高代码质量的几个工具)
- CocosEditor-java中的android项目传数据给Java项目(NodeReader相关)
- java进程间通信:
- 不用‘+’实现加法运算
- 705 - Slash Maze
- java多线程总结:
- 字符全排列、全组合以及相关问题
- NYOJ 题目757 期末考试(贪心)
- Swift泛型(Generics)
- Android动画浅析
- 机器学习中的学习方式-Types of learning