线程B必要等待线程A执行完了methodA()威尼斯人娱乐方法之后,线程间的通信格局

一,介绍

线程间的通讯方式

本总括自身对此JAVA八线程中线程之间的通讯格局的明白,首要以代码结合文字的法门来谈谈线程间的通讯,故摘抄了书中的一些示范代码。

①同步

 

此处讲的同步是指几个线程通过synchronized关键字那种办法来兑现线程间的通信。

二,线程间的通讯形式

参考示例:

①同步

public class MyObject {

    synchronized public void methodA() {
        //do something....
    }

    synchronized public void methodB() {
        //do some other thing
    }
}

public class ThreadA extends Thread {

    private MyObject object;
//省略构造方法
    @Override
    public void run() {
        super.run();
        object.methodA();
    }
}

public class ThreadB extends Thread {

    private MyObject object;
//省略构造方法
    @Override
    public void run() {
        super.run();
        object.methodB();
    }
}

public class Run {
    public static void main(String[] args) {
        MyObject object = new MyObject();

        //线程A与线程B 持有的是同一个对象:object
        ThreadA a = new ThreadA(object);
        ThreadB b = new ThreadB(object);
        a.start();
        b.start();
    }
}

那边讲的一道是指五个线程通过synchronized关键字那种艺术来落到实处线程间的通讯。

出于线程A和线程B持有同一个MyObject类的靶子object,固然那八个线程必要调用不相同的方法,可是它们是一路施行的,比如:线程B需求等待线程A执行完了methodA()方法之后,它才能举行methodB()方法。那样,线程A和线程B就兑现了
通讯。

参考示例:

那种艺术,本质上就是“共享内存”式的通讯。八个线程要求拜访同一个共享变量,哪个人得到了锁(得到了拜访权限),什么人就可以推行。

public class MyObject {

    synchronized public void methodA() {
        //do something....
    }

    synchronized public void methodB() {
        //do some other thing
    }
}

public class ThreadA extends Thread {

    private MyObject object;
//省略构造方法
    @Override
    public void run() {
        super.run();
        object.methodA();
    }
}

public class ThreadB extends Thread {

    private MyObject object;
//省略构造方法
    @Override
    public void run() {
        super.run();
        object.methodB();
    }
}

public class Run {
    public static void main(String[] args) {
        MyObject object = new MyObject();

        //线程A与线程B 持有的是同一个对象:object
        ThreadA a = new ThreadA(object);
        ThreadB b = new ThreadB(object);
        a.start();
        b.start();
    }
}

 

是因为线程A和线程B持有同一个MyObject类的靶子object,即使那三个线程要求调用差别的措施,可是它们是联名施行的,比如:线程B必要等待线程A执行完了methodA()方法之后,它才能执行methodB()方法。那样,线程A和线程B就落实了
通讯。

②while轮询的主意

这种办法,本质上就是“共享内存”式的通讯。多少个线程需要拜访同一个共享变量,哪个人得到了锁(获得了拜访权限),什么人就足以实施。

代码如下:

 

import java.util.ArrayList;
import java.util.List;

public class MyList {

    private List<String> list = new ArrayList<String>();
    public void add() {
        list.add("elements");
    }
    public int size() {
        return list.size();
    }
}

import mylist.MyList;

public class ThreadA extends Thread {

    private MyList list;

    public ThreadA(MyList list) {
        super();
        this.list = list;
    }

    @Override
    public void run() {
        try {
            for (int i = 0; i < 10; i++) {
                list.add();
                System.out.println("添加了" + (i + 1) + "个元素");
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

import mylist.MyList;

public class ThreadB extends Thread {

    private MyList list;

    public ThreadB(MyList list) {
        super();
        this.list = list;
    }

    @Override
    public void run() {
        try {
            while (true) {
                if (list.size() == 5) {
                    System.out.println("==5, 线程b准备退出了");
                    throw new InterruptedException();
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

import mylist.MyList;
import extthread.ThreadA;
import extthread.ThreadB;

public class Test {

    public static void main(String[] args) {
        MyList service = new MyList();

        ThreadA a = new ThreadA(service);
        a.setName("A");
        a.start();

        ThreadB b = new ThreadB(service);
        b.setName("B");
        b.start();
    }
}

②while轮询的办法

在那种方法下,线程A不断地改成规则,线程ThreadB不停地通过while语句检测这么些规则(list.size()==5)是不是创立,从而完成了线程间的通信。不过这种方法会浪费CPU资源。之所以说它浪费资源,是因为JVM调度器将CPU交给线程B执行时,它没做吗“有用”的办事,只是在时时刻刻地测试
某个条件是不是建立。就就如于现实生活中,某个人直接盯先导机显示器是还是不是有电话来了,而不是:
在干其余工作,当有电话来时,响铃公告TA电话来了。
有关线程的轮询的熏陶,可参考:JAVA多线程之当一个线程在执行死循环时会影响其它一个线程吗?

代码如下:

那种办法还留存其余一个题目:

 1 import java.util.ArrayList;
 2 import java.util.List;
 3 
 4 public class MyList {
 5 
 6     private List<String> list = new ArrayList<String>();
 7     public void add() {
 8         list.add("elements");
 9     }
10     public int size() {
11         return list.size();
12     }
13 }
14 
15 import mylist.MyList;
16 
17 public class ThreadA extends Thread {
18 
19     private MyList list;
20 
21     public ThreadA(MyList list) {
22         super();
23         this.list = list;
24     }
25 
26     @Override
27     public void run() {
28         try {
29             for (int i = 0; i < 10; i++) {
30                 list.add();
31                 System.out.println("添加了" + (i + 1) + "个元素");
32                 Thread.sleep(1000);
33             }
34         } catch (InterruptedException e) {
35             e.printStackTrace();
36         }
37     }
38 }
39 
40 import mylist.MyList;
41 
42 public class ThreadB extends Thread {
43 
44     private MyList list;
45 
46     public ThreadB(MyList list) {
47         super();
48         this.list = list;
49     }
50 
51     @Override
52     public void run() {
53         try {
54             while (true) {
55                 if (list.size() == 5) {
56                     System.out.println("==5, 线程b准备退出了");
57                     throw new InterruptedException();
58                 }
59             }
60         } catch (InterruptedException e) {
61             e.printStackTrace();
62         }
63     }
64 }
65 
66 import mylist.MyList;
67 import extthread.ThreadA;
68 import extthread.ThreadB;
69 
70 public class Test {
71 
72     public static void main(String[] args) {
73         MyList service = new MyList();
74 
75         ThreadA a = new ThreadA(service);
76         a.setName("A");
77         a.start();
78 
79         ThreadB b = new ThreadB(service);
80         b.setName("B");
81         b.start();
82     }
83 }

轮询的尺码的可知性问题,关于内存可知性问题,可参照:JAVA多线程之volatile
与 synchronized
的相比
中的第一点“一,volatile关键字的可知性

在那种措施下,线程A不断地转移规则,线程ThreadB不停地经过while语句检测那一个规格(list.size()==5)是还是不是建立
,从而达成了线程间的通信。可是那种措施会浪费CPU资源。之所以说它浪费资源,是因为JVM调度器将CPU交给线程B执行时,它没做什么“有用”的劳作,只是在时时刻刻地测试
某个条件是不是创立。就类似于现实生活中,某个人平素望起首机显示屏是还是不是有电话来了,而不是:
在干其他业务,当有电话来时,响铃公告TA电话来了。
有关线程的轮询的震慑,可参考:JAVA四线程之当一个线程在实施死循环时会影响别的一个线程吗?

线程都是先把变量读取到地头线程栈空间,然后再去再去修改的地面变量。因而,倘若线程B每一次都在取当地的
条件变量,那么即便其它一个线程已经改变了轮询的尺码,它也发现不到,那样也会招致死循环。

那种方法还留存别的一个题目:

 

轮询的基准的可知性问题,关于内存可知性问题,可参照:JAVA三八线程之volatile
与 synchronized
的可比
中的第一点“一,volatile关键字的可知性

③wait/notify机制

线程都是先把变量读取到地面线程栈空间,然后再去再去修改的地头变量。由此,如若线程B每趟都在取当地的
条件变量,那么即使其它一个线程已经改成了轮询的基准,它也意识不到,那样也会导致死循环。

代码如下:

 

import java.util.ArrayList;
import java.util.List;

public class MyList {

    private static List<String> list = new ArrayList<String>();

    public static void add() {
        list.add("anyString");
    }

    public static int size() {
        return list.size();
    }
}


public class ThreadA extends Thread {

    private Object lock;

    public ThreadA(Object lock) {
        super();
        this.lock = lock;
    }

    @Override
    public void run() {
        try {
            synchronized (lock) {
                if (MyList.size() != 5) {
                    System.out.println("wait begin "
                            + System.currentTimeMillis());
                    lock.wait();
                    System.out.println("wait end  "
                            + System.currentTimeMillis());
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


public class ThreadB extends Thread {
    private Object lock;

    public ThreadB(Object lock) {
        super();
        this.lock = lock;
    }

    @Override
    public void run() {
        try {
            synchronized (lock) {
                for (int i = 0; i < 10; i++) {
                    MyList.add();
                    if (MyList.size() == 5) {
                        lock.notify();
                        System.out.println("已经发出了通知");
                    }
                    System.out.println("添加了" + (i + 1) + "个元素!");
                    Thread.sleep(1000);
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class Run {

    public static void main(String[] args) {

        try {
            Object lock = new Object();

            ThreadA a = new ThreadA(lock);
            a.start();

            Thread.sleep(50);

            ThreadB b = new ThreadB(lock);
            b.start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

③wait/notify机制

线程A要等待某个条件知足时(list.size()==5),才实施操作。线程B则向list中添美金素,改变list
的size。

代码如下:

A,B之间什么通讯的吗?也就是说,线程A如何精晓 list.size() 已经为5了呢?

 1 import java.util.ArrayList;
 2 import java.util.List;
 3 
 4 public class MyList {
 5 
 6     private static List<String> list = new ArrayList<String>();
 7 
 8     public static void add() {
 9         list.add("anyString");
10     }
11 
12     public static int size() {
13         return list.size();
14     }
15 }
16 
17 
18 public class ThreadA extends Thread {
19 
20     private Object lock;
21 
22     public ThreadA(Object lock) {
23         super();
24         this.lock = lock;
25     }
26 
27     @Override
28     public void run() {
29         try {
30             synchronized (lock) {
31                 if (MyList.size() != 5) {
32                     System.out.println("wait begin "
33                             + System.currentTimeMillis());
34                     lock.wait();
35                     System.out.println("wait end  "
36                             + System.currentTimeMillis());
37                 }
38             }
39         } catch (InterruptedException e) {
40             e.printStackTrace();
41         }
42     }
43 }
44 
45 
46 public class ThreadB extends Thread {
47     private Object lock;
48 
49     public ThreadB(Object lock) {
50         super();
51         this.lock = lock;
52     }
53 
54     @Override
55     public void run() {
56         try {
57             synchronized (lock) {
58                 for (int i = 0; i < 10; i++) {
59                     MyList.add();
60                     if (MyList.size() == 5) {
61                         lock.notify();
62                         System.out.println("已经发出了通知");
63                     }
64                     System.out.println("添加了" + (i + 1) + "个元素!");
65                     Thread.sleep(1000);
66                 }
67             }
68         } catch (InterruptedException e) {
69             e.printStackTrace();
70         }
71     }
72 }
73 
74 public class Run {
75 
76     public static void main(String[] args) {
77 
78         try {
79             Object lock = new Object();
80 
81             ThreadA a = new ThreadA(lock);
82             a.start();
83 
84             Thread.sleep(50);
85 
86             ThreadB b = new ThreadB(lock);
87             b.start();
88         } catch (InterruptedException e) {
89             e.printStackTrace();
90         }
91     }
92 }

此地运用了Object类的 wait() 和 notify() 方法。

线程A要等待某个条件满足时(list.size()==5),才实施操作。线程B则向list中添加元素,改变list
的size。

当规则未知足时(list.size() !=5),线程A调用wait()
放弃CPU,并跻身阻塞状态。—不像②while轮询那样占用CPU

A,B之间什么通讯的呢?也就是说,线程A怎么着知道 list.size() 已经为5了吧?

当条件知足时,线程B调用 notify()布告线程A,所谓公告线程A,就是提示线程A,并让它进入可运行状态。

此处运用了Object类的 wait() 和 notify() 方法。

那种措施的一个便宜就是CPU的利用率升高了。

当条件未满足时(list.size() !=5),线程A调用wait()
废弃CPU,并跻身阻塞状态。—不像②while轮询那样占用CPU

但是也有部分通病:比如,线程B先举办,一下子添加了5个元素并调用了notify()发送了通报,而此刻线程A还举行;当线程A执行并调用wait()时,那它永远就不能被提醒了。因为,线程B已经发了布告了,未来不再发公告了。那表明:文告过早,会打乱程序的举办逻辑。

当条件满足时,线程B调用 notify()公告线程A,所谓通告线程A,就是提示线程A,并让它进入可运行状态。

 

这种艺术的一个便宜就是CPU的利用率升高了。

④管道通讯纵使接纳java.io.PipedInputStream 和
java.io.PipedOutputStream举行通信

然而也有一部分欠缺:比如,线程B先实施,一下子添加了5个因素并调用了notify()发送了通报,而此刻线程A还实施;当线程A执行并调用wait()时,那它永远就不容许被提示了。因为,线程B已经发了通报了,未来不再发公告了。那注明:照会过早,会打乱程序的实践逻辑。

现实就不介绍了。分布式系统中说的三种通讯机制:共享内存机制和信息通讯机制。感觉前边的①中的synchronized关键字和②中的while轮询
“属于”
共享内存机制,由于是轮询的标准化使用了volatile关键字修饰时,那就意味着它们经过判断这些“共享的口径变量“是还是不是改变了,来贯彻进度间的互换。

 

而管道通讯,更像音讯传递机制,也就是说:通过管道,将一个线程中的音讯发送给另一个。

④管道通讯即便采取java.io.PipedInputStream 和
java.io.PipedOutputStream举办通讯

切实就不介绍了。分布式系统中说的三种通讯机制:共享内存机制和音讯通信机制。感觉前面的①中的synchronized关键字和②中的while轮询
“属于”
共享内存机制,由于是轮询的规则使用了volatile关键字修饰时,那就意味着它们经过判断那个“共享的条件变量“是不是变动了,来落到实处进程间的互换。

而管道通讯,更像信息传递机制,也就是说:通过管道,将一个线程中的信息发送给另一个。

 

关于wait/notify越来越多内容,可参照:JAVA十六线程之wait/notify

相关文章