源无极

导航

 

一、等待、通知之交叉备份

创建20个线程,10个线程备份到A数据库,

另一个10个线程备份到B数据库

要求,备份到数据库的线程交叉进行

package com.it.po.thread10;
public class DBTools {
volatile private boolean prevIsA=false;
synchronized public void backupA(){
    try {
        while (prevIsA==true){
            wait();
        }
        for(int i=0;i<5;i++){
        System.out.println("*****");
        }
        prevIsA=true;
        notifyAll();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
    synchronized public void backupB(){
        try {
            while (prevIsA==false){
                wait();
            }
            for(int i=0;i<5;i++){
                System.out.println("@@@@@");
            }
            prevIsA=false;
            notifyAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

package com.it.po.thread10;
public class MyThread2_1 extends Thread {
private DBTools dbTools;
    public MyThread2_1(DBTools dbTools) {
        this.dbTools = dbTools;
    }
    @Override
    public void run() {
        super.run();
        dbTools.backupA();
    }
}
package com.it.po.thread10;

public class MyThread2_2 extends Thread {
private DBTools dbTools;
    public MyThread2_2(DBTools dbTools) {
        this.dbTools = dbTools;
    }
    @Override
    public void run() {
        super.run();
        dbTools.backupB();
    }
}

 

 

package com.it.po.thread10;
import com.sun.org.apache.bcel.internal.generic.NEW;
public class Run2 {
    public static void main(String[] args) throws InterruptedException {
        DBTools dbTools = new DBTools();
        MyThread2_1[] my1 =  new MyThread2_1[20];
        MyThread2_2[] my2 = new MyThread2_2[20];
        for(int i=0;i<20;i++){
            my1[i]=new MyThread2_1(dbTools);
            my2[i]=new MyThread2_2(dbTools);
            my1[i].start();
            my2[i].start();
        }
    }

}

 

 部分数据

*****
*****
*****
*****
*****
@@@@@
@@@@@
@@@@@
@@@@@
@@@@@
*****
*****
*****
*****
*****
@@@@@
@@@@@
@@@@@
@@@@@
@@@@@

 

 volatile private boolean prevIsA=false;

 该行代码达到了交替备份的效果。

 二、join的使用

          很多情况主线程创建并启动子线程,如果子线程要进行大量的运算

,主线程往往将早于子线程结束之前结束。这是,如果主线程向等待子线程

执行完之后再结束,比如子线程处理一个数据,主线程要取得这个数据

中的值,就要用到join了。 join方法的作用就是等待线程对象销毁。

 

package com.it.po.thread10;

public class MyThread3 extends Thread {
    @Override
    public void run() {
        super.run();
        try {
            int  time = (int) (Math.random() * 10000);//生成0-10s内的值
            System.out.println("time= "+time);
            Thread.sleep(time);//time取得值是不确定的
            System.out.println("MyThread3 线程执行结束了。。。 ");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
package com.it.po.thread10;
public class Run3 {
    public static void main(String[] args) throws InterruptedException {
        MyThread3 myThread3 = new MyThread3();
        myThread3.start();
        //Thread.sleep("??");这应该睡多久?
        //我希望执行完线程myThread3,再执行后面怎么办?
        myThread3.join();
        System.out.println("MyThread3 线程执行结束了,到我了。。。");
    }

}
time= 5448
MyThread3 线程执行结束了。。。 
MyThread3 线程执行结束了,到我了。。。

 

         join方法的作用就是使线程  myThread3 无限期阻塞,直到的等待线程  myThread3

销毁后再执行后面的代码,join具有让线程排队运行的作用,有些类似同步的效果

join 和 sychronized区别

join在内部使用wait()方法进行等待,

sychronized 是使用“ 对象监视器” 原理作为同步。

 join源码

 public final void join() throws InterruptedException {
        join(0);
    }

 

  public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

 

三、join与异常

如果当前线程对象呗中断,则当前线程出现异常

package com.it.po.thread10;
public class MyThred4_1 extends Thread {
    @Override
    public void run() {
        super.run();
        for(int i=0;i<Integer.MAX_VALUE;i++){
            String string = new String();
            string.toString();
        }
    }
}

 

package com.it.po.thread10;
public class MyThred4_2 extends Thread {
    @Override
    public void run() {
        super.run();
        try {
            MyThred4_1 my1 = new MyThred4_1();
            my1.start();
            my1.join();
            System.out.println("我是MyThred4_2线程 执行结束了。。。");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

package com.it.po.thread10;
public class MyThred4_3 extends Thread {
    private MyThred4_2 myThred4_2;
    public MyThred4_3(MyThred4_2 myThred4_2) {
        this.myThred4_2 = myThred4_2;
    }
    @Override
    public void run() {
        super.run();
        myThred4_2.interrupt();
    }
}

 

package com.it.po.thread10;
import com.it.po.thread8.MyThread4_2;
public class Run4 {
    public static void main(String[] args) throws InterruptedException {
        MyThred4_2 myThred4_2 = new MyThred4_2();
        myThred4_2.start();
        Thread.sleep(500);
        MyThred4_3 myThread4_3 = new MyThred4_3(myThred4_2);
        myThread4_3.start();
    }

}
我是MyThred4_2线程 执行结束了。。。
java.lang.InterruptedException
    at java.lang.Object.wait(Native Method)
    at java.lang.Thread.join(Thread.java:1252)
    at java.lang.Thread.join(Thread.java:1326)
    at com.it.po.thread10.MyThred4_2.run(MyThred4_2.java:9)

 

说明:join遇到interrupt会报异常。 但是按钮还是红色

 

 原因是:线程Myread4_1还在执行。所以异常对于Myread4_1是不影响的。

 

四、join(long) 的使用

该方法的设定是等待的时间。

package com.it.po.thread10;
public class MyThread5 extends Thread {
    @Override
    public void run() {
        super.run();
        try {
            System.out.println("begin time "+System.currentTimeMillis());
            Thread.sleep(8000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
package com.it.po.thread10;

public class Run5 {
    public static void main(String[] args) throws InterruptedException {
        MyThread5 myThread5 = new MyThread5();
        myThread5.start();
        myThread5.join(2000);
      System.out.println("end time = "+System.currentTimeMillis());
    }

}

 

begin time 1575082943604
end time = 1575082945605

 

注意:join(2000)是两秒之后会执行main方法

实际两秒之后线程myThread5还是在运行的,知道8s之后才结束

 

 

join(long)和sleep(long)的区别

join(long)功能在内部是使用wait(llong)方法实现的,所以join(long)方法具有释放锁的特点

反之,sleep(long) 是不释放锁的只是把cpu资源让给其他线程。

 

五、join()后面的代码提前运行

package com.it.po.thread10;
public class ThreadA extends Thread {
private ThreadB b;
    public ThreadA(ThreadB b) {
        this.b = b;
    }
    @Override
    public void run() {
        super.run();
        try {
        synchronized (b){
            String name = Thread.currentThread().getName();
            System.out.println("线程 "+name +" begin time= "+System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("线程 "+name +" end time= "+System.currentTimeMillis());
        }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

package com.it.po.thread10;
public class ThreadB extends Thread {
    @Override
  synchronized   public void run() {
        super.run();
        try {
            String name = Thread.currentThread().getName();
            System.out.println("线程 "+name +" begin time= "+System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("线程 "+name +" end time= "+System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

package com.it.po.thread10;

public class Run6 {
    public static void main(String[] args) throws InterruptedException {
        ThreadB b = new ThreadB();
        ThreadA a = new ThreadA(b);
        a.start();
        b.start();
        a.setName("A");
        b.setName("B");
        b.join(2000);
        System.out.println("main   time = "+System.currentTimeMillis());
    }

}

 

结果1:

线程 A begin time= 1575086094626
线程 A end   time= 1575086099626
main   time = 1575086099626
线程 B begin time= 1575086099626
线程 B end   time= 1575086104630

 

结果2

线程 B begin time= 1575086488113
线程 B end time= 1575086493114
main   time = 1575086493114
线程 A begin time= 1575086493114
线程 A end time= 1575086498115

 

结果3

线程 B begin time= 1575086523049
线程 B end   time= 1575086528049
线程 A begin time = 1575086528049
     main   time = 1575086528049
线程 A end time= 1575086533050

 

 

结果1分析:

1) b.join(2000) 先抢到B锁,然后将B锁进行释放

2)线程A抢到锁,打印,并且sleep(2000), 

3)线程A打印结束,并释放锁

4)这时join(2000)和线程B争抢锁,且join(2000)再次抢到锁,发现时间已过,释放锁

打印main 

6)5s过后线程B打印结束。

 

结果3分析

和上面差不多,其实还是

join(2000)和线程B争抢锁,且join(2000)再次抢到锁,发现时间已过,释放锁

注意看打印时间,线程A刚打印begin的时候,这时main    time异步输出

 

 

 

 

 

posted on 2019-11-28 22:58  源无极  阅读(180)  评论(0)    收藏  举报