多线程学习笔记六-------------线程的消亡以及一些常用方法的介绍

多线程wait()和sleep()的区别:
  1、wait()可以指定时间,sleep()必须指定时间。
  2、在同步中时,对cpu的执行权和处理不同。
  wait() 释放执行权,释放锁。
  sleep() 释放执行权,不释放锁。
  在同步锁中(synchronized),多线程可能同时进入锁中(多生产者多消费者问题),都被wait(),此时这些线程都释放了执行权并且释放了锁。
  当有notifyAll()将其唤醒的时候,这些线程都获得了执行权,只有当执行notifyAll()的线程执行完同步锁内的内容的时候才会释放锁,其他线程只有得到
  锁以后才会执行。
线程的消亡:
  停止线程:
  1、stop();-->已过时, 该方法具有固有的不安全性。
  2、void suspend()--> 已过时。 该方法已经遭到反对,因为它具有固有的死锁倾向。
  3、多线程要写循环的原因:因为很多任务要执行很长时间,所以需要开辟一个线程单独执行。
  思路:也就是说线程里面都会有循环,只要控制住循环就能结束任务。如果控制循环呢??控制循环常用的思路就是定于标记来完成的。
  下面介绍一个小demo:

  

public class StopThreadDemo {
        public static void main(String[] args) {
            StopThread st = new StopThread();
            Thread t1 = new Thread(st);
            Thread t2 = new Thread(st);
            t1.start();
            t2.start();
            int num = 0;
            while(true){
                if(++num == 50){
                    st.setFlag();
                    break;
                }
                System.out.println(Thread.currentThread().getName()+"============");
            }
        }
    }
    class StopThread implements Runnable{
        private boolean flag = true;

        public void setFlag() {
            flag = false;
        }

        @Override
        public void run() {
            while(flag){
                System.out.println(Thread.currentThread().getName()+"*************");
            }
        }
    }

虽然这种方式很常用,但是这样的方法会有解决不了的问题:
如果线程处于冻结状态,执行不到setFlag()方法就挂掉了。
例如:

public class StopThreadDemo {
        public static void main(String[] args) {
            StopThread st = new StopThread();
            Thread t1 = new Thread(st);
            Thread t2 = new Thread(st);
            t1.start();
            t2.start();
            int num = 0;
            while(true){
                if(++num == 50){
                    st.setFlag();
                    break;
                }
                System.out.println(Thread.currentThread().getName());
            }
        }
    }
    class StopThread implements Runnable{
        private boolean flag = true;

        public void setFlag() {
            flag = false;
        }

        @Override
        public void run() {
            synchronized(this){
                while(flag){
                    try {
                        System.out.println(Thread.currentThread().getName());
                        wait();
                    } catch (InterruptedException e) {
                        System.out.println(Thread.currentThread().getName()+"******"+e);
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName()+"*************");
            }
        }
    }

  4、 void interrupt() 中断线程。
    如果线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法,
    或者该类的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法过程中受阻,
    则其【中断状态将被清除】,它还将收到一个 InterruptedException。
  我们来看一个示例更容易理解一些:

  

public class StopThreadDemo {
        public static void main(String[] args) {
            StopThread st = new StopThread();
            Thread t1 = new Thread(st);
            Thread t2 = new Thread(st);
            t1.start();
            t2.start();
            int num = 0;
            while(true){
                if(++num == 5){
                    //st.setFlag();
                    t1.interrupt();
                    t2.interrupt();
                    break;
                }
                System.out.println(Thread.currentThread().getName());
            }
        }
    }
    class StopThread implements Runnable{
        private boolean flag = true;

        public void setFlag() {
            flag = false;
        }

        @Override
        public void run() {
            synchronized(this){
                while(flag){
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        System.out.println(Thread.currentThread().getName()+"******"+e);
                        //flag = false;
                    }
                }
                System.out.println(Thread.currentThread().getName()+"*************");
            }
        }
    }

  运行结果
  main
  main
  main
  main
  Thread-0******java.lang.InterruptedException
  Thread-1******java.lang.InterruptedException

  分析:当两个支线程在运行的时候因为执行到了wait()方法,所以进入线程池等待,当主线程执行到t1.interrupt();t2.interrupt();这两句代码的时候,
  两个支线程的等待被清除,并抛出了一个异常 InterruptedException。
  虽然抛出了异常,但是程序并没有终止,而是继续循环,当进入循环的时候又被wait();此时程序便卡在这里。
  此时想要终止线程,在catch中加入flag = false;即可。
  综上:可以使用interrupt()方法将线程从冻结状态强制恢复到运行状态,让线程具备CPU的执行资格。但是因为是强制动作,所以会抛异常,要记得处理。
  守护线程:
    void setDaemon(boolean on) :将该线程标记为守护线程或用户线程。
    将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出(JVM退出意味着只有守护线程的时候,守护线程自动结束)。
    该方法必须在启动线程前调用。
  守护线程示例:

public class StopThreadDemo {
        public static void main(String[] args) {
            StopThread st = new StopThread();
            MyDemo md = new MyDemo();
            Thread t1 = new Thread(st);
            Thread t2 = new Thread(md);
            t1.start();
            t2.setDaemon(true);
            t2.start();
            int num = 0;
            while(true){
                if(++num == 5){
                    t1.interrupt();
                    break;
                }
                System.out.println(Thread.currentThread().getName());
            }
        }
    }
    class StopThread implements Runnable{
        private boolean flag = true;

        public void setFlag() {
            flag = false;
        }
        @Override
        public void run() {
            synchronized(this){
                while(flag){
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        System.out.println(Thread.currentThread().getName()+"******"+e);
                        flag = false;
                    }
                }
                System.out.println(Thread.currentThread().getName()+"*************");
            }
        }
    }
    class MyDemo implements Runnable{
        int count =0 ;
        @Override
        public void run() {
            while(true){
                System.out.println(Thread.currentThread().getName()+"   "+count);
                count++;
            }
        }
    }

运行结果:
main
Thread-1 0
main
Thread-1 1
main
Thread-1 2
main
Thread-1 3
Thread-1 4
Thread-1 5
Thread-0******java.lang.InterruptedException
Thread-1 6
Thread-0*************
Thread-1 7
Thread-1 8
Thread-1 9
Thread-1 10
Thread-1 11
Thread-1 12
分析:如果没有守护线程,Thread-1会不停的执行下去,但是因为有Thread-1线程在开启之前就设置了保护线程,所以当主线程和Thread-0结束后,守护线程也结束了。

下面介绍join()方法:
  public final void join()throws InterruptedException ----> 等待该线程终止。理解:先让该线程执行,该线程结束后再执行主线程。
  示例:

public class JoinDemo {
        public static void main(String[] args) throws InterruptedException {
            MyJoin mj = new MyJoin();
            Thread t1 = new Thread(mj);
            Thread t2 = new Thread(mj);
            t1.start();
            t1.join();
            t2.start();
            for (int i = 0; i < 50; i++) {
                System.out.println("==="+Thread.currentThread().getName()+"===");
            }
        }
    }
    class MyJoin implements Runnable{
        @Override
        public void run() {
            for (int i = 0; i < 20; i++) {
                System.out.println("**********"+Thread.currentThread().getName()+"**********");
            }
        }
    }    

(运行结果太多不展示)
    第一次结果:以上示例的结果表明不管执行多少次都是Thread-0先执行,当Thread-0结束以后其他线程才能执行。
    第二次结果:如果将t1.join();放在t2.start();的下面运行代码,那么执行结果会变得不同。t1和t2是交替执行的,而主线程则在最后执行。
  分析:我们可以得出结论,当下线程如果调用了join()方法,那么主函数会让出CPU的执行权和执行资格,直到该线程结束,而对其他线程没有影响。
    第一次结果是因为一开始加载还没有启动t2线程,主函数便让出了CPU的执行权和执行资格,所以t2不会出现。
    第二次结果是因为t2线程已经启动,即便是主函数让出了CPU的执行权和执行资格,也只是针对于t1而言的,所以不影响t2的运行。
  join()的运行场景:需要临时加入一个线程运算时候可以用join()方法。当然join也可以带参数的,使用时查看API即可。
介绍线程优先级:
  void setPriority(int newPriority) :更改线程的优先级。
    static int MAX_PRIORITY -->10
    线程可以具有的最高优先级。
    static int MIN_PRIORITY -->1
    线程可以具有的最低优先级。
    static int NORM_PRIORITY -->5
    分配给线程的默认优先级。
  线程的优先级共有1-10,为了方便提供了上述静态变量供使用。默认情况下线程的优先级都是5。
  注意:线程的优先级只能保证该线程在长时间的多线程任务中获得执行资格后可以多占用一点时间,其实线程还是抢占式的,而不是霸占了执行权和执行资格直到自己执行完。
介绍线程组:
  public class ThreadGroup:该类的出现,将线程分组,便于管理线程。
yield()方法:
  public static void yield(): 暂停当前正在执行的线程对象,并执行其他线程。
  最后有两道题:
1、下面程序回报什么错?

class Test implements Runnable{
    public void run(Thread t){

    }
}

2、分析并得出下列代码的结果

ublic class Demo{
    public static void main(String[] args){
        new Thread(new Runnable(){
            public void run(){
                System.out.println("Runnable");
            }
        }){
            public void run(){
                System.out.println("subThread");
            }
        }.start();
    }
}

如果子类没有重写run()方法呢?

public class Demo{
    public static void main(String[] args){
        new Thread(new Runnable(){
            public void run(){
                System.out.println("Runnable");
            }
        }){
        }.start();
    }
}

如果也没有任务呢?

public class Demo{
    public static void main(String[] args){
        new Thread(){
        }.start();
    }
}

答案:
1、因为Test类实现了Runnable接口,就必须实现它的方法,如果不实现它的方法,那么必须是抽象类,所以用abstract来修饰Test。
2、subThread Runnable 无

时间: 2024-10-11 07:17:58

多线程学习笔记六-------------线程的消亡以及一些常用方法的介绍的相关文章

JAVA多线程学习笔记&lt;3&gt;线程传入参数与终止线程方法

public class TimeThread extends Thread { private long start; public volatile boolean exit = false; public TimeThread(long start) { this.start = start; } public void run() { while(!exit) { long end = System.currentTimeMillis(); long useTime = end - st

多线程学习笔记四--------------线程间通信问题

线程间通信问题: 多个线程在处理同一资源,但是任务却不同: java中将资源共享的方法(思路): 1.方法或者变量静态化---->静态化后,在类加载的时候,会将其加载到内存的方法区进行共享 2.单例设计模式---->保证只对一个实例进行操作. 3.将资源作为操作该资源的类的构造函数的参数,这样可以保证此类的多个对象在使用该资源的时候使用该资源的同一个实例. 现在我们要用第三种方法来进行线程间的通信. 情景:两个线程 ,一个负责输入,一个负责输出:共同处理一个资源. public class T

操作系统学习笔记----进程/线程模型----Coursera课程笔记

操作系统学习笔记----进程/线程模型----Coursera课程笔记 进程/线程模型 0. 概述 0.1 进程模型 多道程序设计 进程的概念.进程控制块 进程状态及转换.进程队列 进程控制----进程创建.撤销.阻塞.唤醒.... 0.2 线程模型 为什么引入线程 线程的组成 线程机制的实现 用户级线程.核心级线程.混合方式 1. 进程的基本概念 1.1 多道程序设计 允许多个程序同时进入内存运行,目的是为了提高CPU系统效率 1.2 并发环境与并发程序 并发环境: 一段时间间隔内,单处理器上

java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)

java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessController的checkPerssiom方法,访问控制器AccessController的栈检查机制又遍历整个 PerssiomCollection来判断具体拥有什么权限一旦发现栈中一个权限不允许的时候抛出异常否则简单的返回,这个过程实际上比我的描述要复杂 得多,这里我只是简单的一句带过,因为这

Linux System Programming 学习笔记(七) 线程

1. Threading is the creation and management of multiple units of execution within a single process 二进制文件是驻留在存储介质上,已被编译成操作系统可以使用,准备执行但没有正运行的休眠程序 进程是操作系统对 正在执行中的二进制文件的抽象:已加载的二进制.虚拟内存.内核资源 线程是进程内的执行单元 processes are running binaries, threads are the smal

Win32 多线程学习笔记

学到的API函数 一.线程 创建线程.结束线程.获取线程的结束码 CreateThread ExitThread GetExitCodeThread 二.线程结束时触发 创建线程之后,等待线程的结束之后,再继续执行 WaitForSingleObject 创建多个线程之后,等待一组线程(或其中的一个)结束,再继续执行 WaitForMultipleObjects 将消息循环与内核对象的等待合并 MsgWaitForMultipleObjects 三.同步 SendMessage 是同步的 Pos

python之raw_input()(学习笔记六)

python之raw_input()(学习笔记六) 我们经常使用raw_input()读取用户的输入,如下例子所示: >>> name = raw_input('please input your name:'),截图如下: 下面简单说下,raw_input()与if搭配使用,脚本如下: #!/usr/bin/env python # -*- coding:utf-8 -*- birth = raw_input('birth:') if birth < 2000: print '0

swift学习笔记(六)析构过程和使用闭包对属性进行默认值赋值

一.通过闭包和函数实现属性的默认值 当某个存储属性的默认值需要定制时,可以通过闭包或全局函数来为其提供定制的默认值. 注:全局函数结构体和枚举使用关键字static标注    函数则使用class关键字标注 当对一个属性使用闭包函数进行赋值时,每当此属性所述的类型被创建实例时,对应的闭包或函数会被调用,而他们的返回值会被作为属性的默认值. ESC: Class SomeCLass{ let someProperty:SomeType={ //给someProperty赋一个默认值 //返回一个与

初探swift语言的学习笔记六(ARC-自动引用计数,内存管理)

Swift使用自动引用计数(ARC)来管理应用程序的内存使用.这表示内存管理已经是Swift的一部分,在大多数情况下,你并不需要考虑内存的管理.当实例并不再被需要时,ARC会自动释放这些实例所使用的内存. 另外需要注意的: 引用计数仅仅作用于类实例上.结构和枚举是值类型,而非引用类型,所以不能被引用存储和传递. swift的ARC工作过程 每当创建一个类的实例,ARC分配一个内存块来存储这个实例的信息,包含了类型信息和实例的属性值信息. 另外当实例不再被使用时,ARC会释放实例所占用的内存,这些