多线程通讯方式

  多线程的通讯方式有如下几种方式,今天我们首先简绍线程通讯之共享内存

  1.共享内存

  首先,我们通过一个经典的多线程案例开启我们的多线程的之旅。

子线程执行10次,主线程执行100次,两者交替50次。  

package com.sort.test;

public class SynThreadTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //子线程执行10次,主线程执行100次,两者交替50次。
        //业务对象必须是同一个对象(这里指tran这个对象),不能是两个对象,两个对象的同步方法不会互斥,也就达不到同步的效果了
        final Transacion tran = new Transacion();
        //启动子线程
        new Thread(new Runnable() {
            
            @Override
            public void run() {
                // TODO Auto-generated method stub
                for(int i = 0; i < 10; i++){
                    tran.sub(i);
                }
            }
        }).start();
        //主线程中执行50次
        for(int i = 0; i < 10; i++){
            tran.main(i);
        }
    }
    
    
}
/**
 * 业务类
 * @author zhangli
 *
 */
class Transacion{
    //共享内存中的共享变量
    private boolean isMainTurn = false; 
    public synchronized void main(int j){
        //首先判断是否是主线程轮次,如果是ture,则主线程执行100次,否则主线程等待
        if(!isMainTurn){
            try {
                this.wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        //完成主线程任务
        for (int i = 0 ; i < 100 ;i++){
            
            System.out.println("主线程执行第"+j+"次"+"序号为"+i);
        }
        //执行100次后,主线程本轮执行完毕,改变共享变量通知子线程执行
        isMainTurn = false;
        //释放this锁,并且唤醒等待此对象的上的子线程,让它进入就绪状态
        this.notify();
    }
    public synchronized void sub(int j){
        //首先判断是否是子线程轮次,如果是false,则子线程执行10次,否则子线程等待
        if(isMainTurn){
            try {
                this.wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        //完成子线程任务
        for (int i = 0 ; i < 10 ;i++){
            System.out.println("子线程执行第"+j+"次"+"序号为"+i);
        }
        //执行10次后,子线程本轮执行完毕,改变共享变量通知子线程执行
        isMainTurn = true;
        //释放this锁,并且唤醒等待此对象的上的主线程,让它进入就绪状态
        this.notify();
    }
}

  执行结果如下:

主线程执行第0次序号为86
主线程执行第0次序号为87
主线程执行第0次序号为88
主线程执行第0次序号为89
主线程执行第0次序号为90
主线程执行第0次序号为91
主线程执行第0次序号为92
主线程执行第0次序号为93
主线程执行第0次序号为94
主线程执行第0次序号为95
主线程执行第0次序号为96
主线程执行第0次序号为97
主线程执行第0次序号为98
主线程执行第0次序号为99
123123
子线程执行第1次序号为0
子线程执行第1次序号为1
子线程执行第1次序号为2
子线程执行第1次序号为3
子线程执行第1次序号为4
子线程执行第1次序号为5
子线程执行第1次序号为6
子线程执行第1次序号为7
子线程执行第1次序号为8
子线程执行第1次序号为9
主线程执行第1次序号为0
主线程执行第1次序号为1
主线程执行第1次序号为2
主线程执行第1次序号为3
主线程执行第1次序号为4
主线程执行第1次序号为5
主线程执行第1次序号为6
主线程执行第1次序号为7
主线程执行第1次序号为8
主线程执行第1次序号为9
主线程执行第1次序号为10
主线程执行第1次序号为11

  在此案例中,我们是利用同一个对象tran的isMainTurn属性完成多线程通讯的,通过改变isMainTurn的属性值以判断该是哪个线程的轮次,这样完成了线程的同步和通讯。

  总结:

  1.共享变量必须是同一个对象(这里指tran这个对象),不能是两个对象,两个对象的同步方法不会互斥,也就达不到同步的效果了

  2.在利用共享变量处理多线程问题时,我们最好根据实际定义一个业务类,也就是把我们要同步的多个任务最好封装到一个业务类中,这样我们就可以通过一个业务类对象完成多个任务的同步了。

  3.锁都是加在对象上(tran)的,而不是加在方法上的

  4.wait方法会立刻阻塞本次线程执行,而且释放线程上的对象锁;而notify也会释放线程上的对象锁,但不会阻塞线程的执行。