/* 1.增加一个知识点 一个类怎么在所有的类中,让其它类来共同修改它的数据呢? 可以用单例设计模式 可以用静态 可以在其它类中做一个构造函数,接受同一个对象,这样就可以实现对象
2.状态选择 可以用数字0 1 判断 可以用bool 注意变量的范围即可
3.加了同步后,还是有安全怎么办? 想前提! 1. 两个及以上线程(同步的) 2.操作公用资源 3.要用同一锁 */
/* 线程间通讯: 其实就是多个线程在操作同一个资源, 但是操作的动作不同。
*/
/* 1.为什么会出现安全问题? 就是不满足前提呗
2.我们还没有了解到线程的本质 1.线程的执行时互相争抢执行权的 2.如果没有同步代码块的话,就会对数据进行胡乱修改,有可能修改到一半,另一个线程进来,有可能修改好几次,等等,甚至还会无视条件 3.即便有了同步代码块,也不能保证代码是按次序相互执行,因为,第一个线程执行完之后,还会参与下一次的争抢当中来,拥有相同的争抢概率 所以就出现同步中的不同步状况,这时候就要用到唤醒 4.其实程序就是一个逻辑判断问题,就是看有没有数据 */
/*五种状态之一的等待 1.是Thread从上帝那里继承来的 2.而且这个函数是抛了异常的,根据异常的格式,要try和catch 3.唤醒也是继承上帝的 4.使用的时候,直接用对象点出来就可以 5.这样很容易区分,也造成为什么要把这两个函数写在上帝里面的原因,锁是任意类型的,什么对象都可以
*/ class Res /*定义一个类,里面封装好数据成员,用来去调用*/ { String name; String sex; boolean flag = false; /*用来判断是否已经存入数据,封装好用来调用*/ }
class Input implements Runnable { private Res r ; Input(Res r) { this.r = r; } public void run() { int x = 0; while(true) { synchronized(r) /*只能让一个线程进来,而且输入的先进来,输出的就不给进了,这样就满足了前提,有两个线程,同一锁,公共资源*/ {
if(r.flag) /*真,冻结*/ try{r.wait();}catch(Exception e){} /*线程池,等待线程都在线程池当中,唤醒的是什么,唤醒的都是线程池当中的线程*/ if(x==0) { r.name="mike"; /*赋值*/ r.sex="man"; } else { r.name="丽丽"; r.sex = "女女女女女"; } x = (x+1)%2; /*转换性别*/ r.flag = true; r.notify(); /*有就唤醒,没有就不唤醒,按顺序来自然就不需要这个,唤醒的是另一个线程*/ } } } }
class Output implements Runnable { private Res r ; /*对象数据成员*/ Output(Res r) { this.r = r; /*传递对象进来*/ } public void run() { while(true) { synchronized(r) /*放的是对象*/ { if(!r.flag) try{r.wait();}catch(Exception e){} System.out.println(r.name+"...."+r.sex); /*删除*/ r.flag = false; r.notify(); /*唤醒输入线程*/ } } } }
class InputOutputDemo { public static void main(String[] args) { Res r = new Res(); /*封装好的类,将会当作参数,传递给其它类*/
Input in = new Input(r); /*实现多线程类的对象*/ Output out = new Output(r);
Thread t1 = new Thread(in); /*开启线程,把实现线程的对象放进来*/ Thread t2 = new Thread(out);
t1.start(); /*开启线程,调用run函数*/ t2.start(); } }
//notifyAll();
/* wait: notify(); notifyAll();
都使用在同步中,因为要对持有监视器(锁)的线程操作。 所以要使用在同步中,因为只有同步才具有锁。
为什么这些操作线程的方法要定义Object类中呢? 因为这些方法在操作同步中线程时,都必须要标识它们所操作线程只有的锁, 只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒。 不可以对不同锁中的线程进行唤醒。
也就是说,等待和唤醒必须是同一个锁。
而锁可以是任意对象,所以可以被任意对象调用的方法定义Object类中。
*/
代码优化: /* 线程间通讯: 其实就是多个线程在操作同一个资源, 但是操作的动作不同。
*/ class Res { private String name; private String sex; private boolean flag = false;
public synchronized void set(String name,String sex) { if(flag) try{this.wait();}catch(Exception e){} /*记住,加同步的是共同操作的数据,不是定义数据,是会变动的数据*/ this.name = name; this.sex = sex; flag = true; this.notify(); /*this代表同步函数的锁,也代表当前对象*/ } public synchronized void out() { if(!flag) try{this.wait();}catch(Exception e){} System.out.println(name+"........"+sex); flag = false; this.notify(); } }
class Input implements Runnable { private Res r ; /*用来接收同一个对象*/ Input(Res r) { this.r = r; } public void run() { int x = 0; while(true) { if(x==0) r.set("mike","man"); /*这个函数已经是同步函数了*/ else r.set("丽丽","女女女女女"); x = (x+1)%2; } } }
class Output implements Runnable { private Res r ; Output(Res r) { this.r = r; } public void run() { while(true) { r.out(); /*不断输出*/ } } }
class InputOutputDemo2 { public static void main(String[] args) { Res r = new Res();
new Thread(new Input(r)).start(); /*全部使用无名对象,优化代码*/ new Thread(new Output(r)).start(); /* Input in = new Input(r); Output out = new Output(r);
Thread t1 = new Thread(in); Thread t2 = new Thread(out);
t1.start(); t2.start(); */ } }
|