java---多线程-02

线程API

   sleep阻塞

   sleep方法处理异常:InterruptedException.

    当一个线程调用sleep方法处于睡眠阻塞的过程中,该线程的interrupt()方法被调用时,sleep方法会抛出该异常从而打断睡眠阻塞.


package thread;

/**
 * sleep方法要求必须处理中断异常:InterruptedException
 * 当一个线程调用sleep方法处于睡眠阻塞的过程中,它的interrupt()方法被调用时
 * 会中断该阻塞,此时sleep方法会抛出该异常。
 */
public class SleepDemo2 {
    public static void main(String[] args) {
        Thread lin = new Thread(){
            public void run(){
                System.out.println("林:刚美完容,睡一会吧~");
                try {
                    Thread.sleep(9999999);
                } catch (InterruptedException e) {
                    System.out.println("林:干嘛呢!干嘛呢!干嘛呢!都破了像了!");
                }
                System.out.println("林:醒了");
            }
        };

        Thread huang = new Thread(){
            public void run(){
                System.out.println("黄:大锤80!小锤40!开始砸墙!");
                for(int i=0;i<5;i++){
                    System.out.println("黄:80!");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                    }
                }
                System.out.println("咣当!");
                System.out.println("黄:大哥,搞定!");
                lin.interrupt();//中断lin的睡眠阻塞
            }
        };
        lin.start();
        huang.start();
    }
}

 守护线程

守护线程也称为:后台线程

- 守护线程是通过普通线程调用setDaemon(boolean on)方法设置而来的,因此创建上与普通线程无异.
- 守护线程的结束时机上有一点与普通线程不同,即:进程的结束.
- 进程结束:当一个进程中的所有普通线程都结束时,进程就会结束,此时会杀掉所有正在运行的守护线程.


package thread;

/**
 * 守护线程
 * 守护线程是通过普通线程调用setDaemon(true)设置而转变的。因此守护线程创建上
 * 与普通线程无异。
 * 但是结束时机上有一点不同:进程结束。
 * 当一个java进程中的所有普通线程都结束时,该进程就会结束,此时会强制杀死所有正在
 * 运行的守护线程。
 */
public class DaemonThreadDemo {
    public static void main(String[] args) {
        Thread rose = new Thread(){
            public void run(){
                for(int i=0;i<5;i++){
                    System.out.println("rose:let me go!");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                    }
                }
                System.out.println("rose:啊啊啊啊啊啊AAAAAAAaaaaa....");
                System.out.println("噗通");
            }
        };

        Thread jack = new Thread(){
            public void run(){
                while(true){
                    System.out.println("jack:you jump!i jump!");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                    }
                }
            }
        };
        rose.start();
        jack.setDaemon(true);//设置守护线程必须在线程启动前进行
        jack.start();

    }
}

    通常当我们不关心某个线程的任务什么时候停下来,它可以一直运行,但是程序主要的工作都结束时它应当跟着结束时,这样的任务就适合放在守护线程上执行.比如GC就是在守护线程上运行的.

 join方法

   线程提供了一个方法:void join()

  - 该方法允许调用这个方法的线程在该方法所属线程上等待(阻塞),直到该方法所属线程结束后才会 解除等待继续后续的工作.所以join方法可以用来协调线程的同步运行.
 - 同步运行:多个线程执行过程存在先后顺序进行.
 - 异步运行:多个线程各干各的.线程本来就是异步运行的.


package thread;

/**
 * 线程提供了一个join方法,可以协调线程的同步运行。它允许调用该方法的线程等待(阻塞),
 * 直到该方法所属线程执行完毕后结束等待(阻塞)继续运行。
 *
 * 同步运行:多个线程执行存在先后顺序。
 * 异步运行:多个线程各干各的,线程间运行本来就是异步的。
 */
public class JoinDemo {
    //图片是否下载完毕
    public static boolean isFinish = false;

    public static void main(String[] args) {
        /*
            当一个方法的局部内部类中引用了这个方法的其他局部变量时,这个变量
            必须是final的。
         */
//        final boolean isFinish = false;
        Thread download = new Thread(){
            public void run(){
                for(int i=1;i<=100;i++){
                    System.out.println("down:"+i+"%");
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                    }
                }
                System.out.println("down:下载完毕!");
                isFinish = true;
            }
        };

        Thread show = new Thread(){
            public void run(){
                try {
                    System.out.println("show:开始显示文字...");
                    Thread.sleep(3000);
                    System.out.println("show:显示文字完毕!");
                    /*
                        显示图片前要等待download执行完毕
                     */
                    System.out.println("show:开始等待download...");
                    download.join();//show线程阻塞,直到download执行完毕
                    System.out.println("show:等待download完毕!");

                    System.out.println("show:开始显示图片...");
                    if(!isFinish){
                        throw new RuntimeException("show:显示图片失败!");
                    }
                    System.out.println("show:显示图片完毕!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        download.start();
        show.start();
    }
}

多线程并发安全问题


    当多个线程并发操作同一临界资源,由于线程切换时机不确定,导致操作临界资源的顺序出现混乱严重时可能导致系统瘫痪.
    临界资源:操作该资源的全过程同时只能被单个线程完成.


package thread;

/**
 * 多线程并发安全问题
 * 当多个线程并发操作同一临界资源,由于线程切换的时机不确定,导致操作顺序出现
 * 混乱,严重时可能导致系统瘫痪。
 * 临界资源:同时只能被单一线程访问操作过程的资源。
 */
public class SyncDemo {
    public static void main(String[] args) {
        Table table = new Table();
        Thread t1 = new Thread(){
            public void run(){
                while(true){
                    int bean = table.getBean();
                    Thread.yield();
                    System.out.println(getName()+":"+bean);
                }
            }
        };
        Thread t2 = new Thread(){
            public void run(){
                while(true){
                    int bean = table.getBean();
                    /*
                        static void yield()
                        线程提供的这个静态方法作用是让执行该方法的线程
                        主动放弃本次时间片。
                        这里使用它的目的是模拟执行到这里CPU没有时间了,发生
                        线程切换,来看并发安全问题的产生。
                     */
                    Thread.yield();
                    System.out.println(getName()+":"+bean);
                }
            }
        };
        t1.start();
        t2.start();
    }
}

class Table{
    private int beans = 20;//桌子上有20个豆子

    public int getBean(){
        if(beans==0){
            throw new RuntimeException("没有豆子了!");
        }
        Thread.yield();
        return beans--;
    }
}

总结:

  1. sleep方法: sleep方法是Thread类的一个静态方法,用于暂停当前线程的执行一段时间。它接受一个以毫秒为单位的时间参数,指示当前线程暂停的时间长度。在sleep期间,线程不会执行任何操作,但它仍然占用系统资源。

       sleep方法的使用可以用于以下情况:

  • 在多线程程序中,控制线程的执行顺序。
  • 在需要等待某些条件满足时,暂时让线程休眠。
  1. 守护线程: 守护线程是指在后台执行的线程,它通常被用来执行一些系统级任务,如垃圾回收。守护线程的生命周期会被设置为与JVM主线程的生命周期相同。当所有的非守护线程结束时,JVM会自动关闭所有的守护线程。

守护线程的创建和启动方式与普通线程相同,只需在调用start()方法之前,使用setDaemon(true)方法将线程设置为守护线程。

     守护线程的使用场景:

  • 执行一些不需要完全执行完的任务,如日志记录。
  • 执行一些周期性的任务,如定时器。
  1. join方法: join方法是Thread类的一个方法,用于让一个线程等待另一个线程执行完毕。调用某个线程的join方法会让当前线程进入等待状态,直到被调用线程执行完毕或超时。

       join方法可以用于以下情况:

  • 确保线程的执行顺序,使得当前线程在另一个线程执行完毕后再继续执行。
  • 在主线程中等待子线程完成任务。

      join方法有两种重载方式:

  • join():等待被调用线程执行完毕。
  • join(long millis):等待被调用线程执行完毕,最多等待millis毫秒。

需要注意的是,join方法只能在当前线程内部调用,即在run方法或其他线程内部调用join方法会导致程序死锁。

 sleep方法用于暂停当前线程的执行一段时间,守护线程用于后台执行任务,join方法用于等待另一个线程执行完毕。

      

你可能感兴趣的:(java,开发语言)