zoukankan      html  css  js  c++  java
  • Java 多线程系列01

    1. 进程和线程

      进程是一个应用程序,每个进程都有自己的独立内存空间,进程不依赖线程而独立存在,一个进程可以启动多个线程。

      线程是进程的执行单元,一个进程可以运行多个线程。

      在Dos中输入java HelloWorld后,程序的执行过程:

      会先启动Jvm,Jvm就是一个进程,Jvm在启动一个主线程执行main方法,在启动一个垃圾回收线程负责看护,回收垃圾,至少有两个线程并发运行,一个垃圾回收线程,一个执行main方法的线程。

      在Java中,线程A和线程B,堆内存和方法区内存共享,但是栈内存独立,一个线程一个栈;所以main方法结束了,只代表主线程结束了,其他线程可能还在执行。

    2. 线程的生命周期

    • 新建状态

        线程创建后,就进入新建状态。例如:Thread thread = new Thread();。

    • 就绪状态:   

        当线程对象调用了start()方法后,线程就进入了就绪状态,等待CPU调度。

    • 运行状态:  

        线程获取CPU资源,就可以运行,就处于运行状态。

    • 阻塞状态:  

        线程因为其他原因失去CPU资源暂时停止运行。直到线程进入就绪状态,才可以重新进入运行状态。阻塞状态有三种:

       (1)等待阻塞:线程执行wait()方法,就进入等待阻塞状态。

       (2)同步阻塞:线程获取synchronized同步锁失败(同步锁被其他线程占用中)

       (2)其他阻塞:通过调用sleep()或join()发出I/O请求时,进入阻塞状态。

    • 死亡状态:  

        线程执行完成或被其他任务强制终止

    3. 实现线程的两种方式

      通过继承Thread创建线程

    public class ThreadTest01{
        public static void main(String[] args){
            MyThread thread = new MyThread();
            thread.start();
            
            for(int i=0; i<1000; i++){
                System.out.println("主线程----" + i);
            }
        }
    }
    
    class MyThread extends Thread{
        public void run(){
            for(int i=0; i<1000; i++){
                System.out.println("分支线程----" + i);
            }
        }
    }

      结果说明:

        如果单纯调用MyThread.run(),那么只是在main()方法上压栈,没有创建分支线程;

        先调用start()方法开辟一个分支栈空间,然后会自动调用run(),在分支栈中和主栈中并发同时输出。

      实现Runnable接口创建线程

    public class ThreadTest02{
        public static void main(String[] args){
            Thread thread = new Thread(new MyRunnable());    //创建一个可运行对象,创建接口,把可运行对象封装成线程对象
            thread.start();
            
            for(int i=0; i<1000; i++){
                System.out.println("主线程----" + i);
            }
        }
    }
    
    class MyRunnable implements Runnable{
        public void run(){
            for(int i = 0; i<1000; i++){
                System.out.println("分支线程----" + i);
            }
        }
    }

    4. 线程方法

      (1)getName()  获取线程名,默认线程名Thread-0;

      (2)setName()  设置线程名;

      (3)Thread.currentThread()  获取当前线程名,返回Thread,在哪个线程中就获取哪个线程名

    public class ThreadTest03{
        public static void main(String[] args){
            Thread currentThread = Thread.currentThread();
            System.out.println("当前线程:" + currentThread.getName());
            
            MyThread mt = new MyThread();
            mt.setName("tt");
            System.out.println(mt.getName());
            mt.start();
        }
    }
    
    class MyThread extends Thread{
        public void run(){
            for(int i = 0; i<5; i++){
                Thread currentThread = Thread.currentThread();
                System.out.println(currentThread.getName() + "分支线程:" + i);
            }
        }
    }

      Thread.sleep(long mills)  让当前线程等待mills(毫秒)

    public class ThreadTest04{
        public static void main(String[] args){
            for(int i=0; i<5; i++){
                System.out.println(Thread.currentThread().getName() + "----" + i);
                try{
                    Thread.sleep(1000);
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
        }
    }

      interrupt()  线程中断

    public class ThreadTest05{
        public static void main(String[] args){
            Thread t = new Thread(new MyRunnable());
            t.setName("tt");
            t.start();
            
            try{
                Thread.sleep(5000);
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            
            t.interrupt();
        }
    }
    
    class MyRunnable implements Runnable{
        public void run(){
            System.out.println(Thread.currentThread().getName() + "---start");
            
            try{
                Thread.sleep(1000*60*60*24*365);  //父类中没有抛出异常,子类中只能try...catch...捕获异常
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            
            System.out.println(Thread.currentThread().getName() + "---end");
        }
    }

     

      当线程被wait,sleep,join等阻塞时,调用该线程的interrupt()方法,那么该线程将抛出一个InterruptedException异常(该线程必须提前处理此异常),从而提早的终结被阻塞状态。如果线程没有被阻塞,这是调用interrupt()将不起作用。线程被唤醒的机制也是异常处理机制,当有异常发生时,就可以唤醒线程。

      

      stop()  终止线程

    public class ThreadTest06{
        public static void main(String[] args){
            MyRunnable mr = new MyRunnable();
            Thread t = new Thread(mr);
            t.setName("tt");
            t.start();
            
            try{
                Thread.sleep(5000);
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            
            //t.stop();
            mr.flag = false;
        }
    }
    
    class MyRunnable implements Runnable{
        boolean flag = true;
        public void run(){
            for(int i=0; i<10; i++){
                if(flag){
                    System.out.println(Thread.currentThread().getName() + "---" + i);
                    try{
                        Thread.sleep(1000);
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }
                }else{
                    return;
                }
            }
        }
    }

      stop() 终止线程因为安全性问题,现在已经不推荐使用。

    5. 线程调度

      getPriority()  获取线程优先级

      setPriority()  设置线程优先级

    public class ThreadTest07{
        public static void main(String[] args){
        /*    System.out.println(Thread.currentThread().getName() + "优先级:" + Thread.currentThread().getPriority());
            ThreadTest t = new ThreadTest();
            t.setName("tt");
            t.start();
            System.out.println("线程的最高优先级:"+Thread.MAX_PRIORITY); //10
            System.out.println("线程的最低优先级:"+Thread.MIN_PRIORITY); //1
            System.out.println("线程的正常优先级:"+Thread.NORM_PRIORITY); //5  */
            
            ThreadTest tt = new ThreadTest();
            tt.setName("tt");
            tt.setPriority(10);
            tt.start();
            for(int i=0; i<1000; i++){
                System.out.println(Thread.currentThread().getName() + "--->" + i);
            }
            
        }
    }
    
    class ThreadTest extends Thread{
        public void run(){
            //System.out.println(Thread.currentThread().getName() + "优先级:" + Thread.currentThread().getPriority());
            
            for(int i=0; i<1000; i++){
                System.out.println(Thread.currentThread().getName() + "--->" + i);
            }
            
            
        }
    }

      线程优先级的范围是1-10,默认优先级是5。

      高优先级线程被分配CPU的概率高于低优先级线程,但是无论级别相同还是不同,线程调度都不对绝对按照优先级执行,根据时间片轮询调度,并发执行。

      yield()  线程让位,让线程暂停回到就绪状态

    public class ThreadTest08{
        public static void main(String[] args){
            Thread th = new Thread(new yieldTest());
            th.setName("tt");
            th.start();
            
            for(int i=0; i<10000; i++){
                System.out.println(Thread.currentThread().getName() + "--->" + i);
            }
        }
    }
    
    class yieldTest implements Runnable{
        public void run(){
            for(int i=0; i<10000; i++){
                if(i % 100 == 0){    
                    Thread.yield();    //每过100,让位给主线程
                }
                System.out.println(Thread.currentThread().getName() + "--->" + i);
            }
            
        }
    }

      yield()作用时让步,让当前线程由运行状态进入到就绪状态,从而让其他具有相同优先级的线程获取执行权;但是并不能保证当前线程调用yield后,其他线程线程就一定能获取执行权,也有可能当前线程又继续进入运行状态。

      join() 线程合并,让主线程等待子线程执行完后再继续执行主线程。

    public class ThreadTest09{
        public static void main(String[] args){
            System.out.println("main begin");
            Thread th = new Thread(new joinTest());
            th.setName("tt");
            th.start();
            try{
                th.join();   //加入到主线程中,执行完后,再执行其他线程
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            System.out.println("main over");
        }
    }
    
    class joinTest implements Runnable{
        public void run(){
            for(int i=0; i<100; i++){
                System.out.println(Thread.currentThread().getName() + "--->" + i);
            }
        }
    }

    6. 守护线程  

      setDaemon() 守护线程,一般是死循环,只要主线程结束,守护线程就自动结束

    public class ThreadTest10{
        public static void main(String[] args){
            Thread th = new Thread(new MyThread());
            th.setName("备份数据线程");
            th.setDaemon(true);    //备份数据线程设置为用户线程的守护线程,用户线程结束,备份数据线程结束
            th.start();
            
            //用户线程
            for(int i=0; i<10; i++){
                System.out.println(Thread.currentThread().getName() + "--->" + i);
                try{
                    Thread.sleep(1000);
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
            }
        }
    }
    
    class MyThread implements Runnable{
        int i=0;
        public void run(){
            while(true){
                System.out.println(Thread.currentThread().getName() + "--->" + (++i));
                try{
                    Thread.sleep(1000);
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
            }
        }
    }

     7. 线程等待(wait)与唤醒(notify(),notifyAll())

      wait()和notify(),notifyAll()都是Object.java中的方法

      wait()的作用是让当前线程进入等待状态,同时会释放当前线程的锁;

      notify()的作用是唤醒单个线程;  

      notifyAll()的作用是唤醒所有线程;

    public class ThreadTest14{
        public static void main(String[] args){
            MyThread mt = new MyThread("t1");
            
            synchronized(mt){
                try{
                    System.out.println(Thread.currentThread().getName() + " start mt");
                    mt.start();
                    System.out.println(Thread.currentThread().getName() + " wait");
                    mt.wait();
                    System.out.println(Thread.currentThread().getName() + " continue");
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
            }
            
        }
    }
    
    class MyThread extends Thread{
        public MyThread(String name){
            super(name);
        }
        public void run(){
            synchronized(this){
                System.out.println(Thread.currentThread().getName() + " call notify");  //当前线程被唤醒
                notify();
            }
        }
    }
    //运行结果
    main start mt main wait t1 call notify main
    continue

      t1.wait()是在主线程main中调用,而主线程是当前线程,因此t1.wait()是让主线程等待!

      

      notifyAll()唤醒所有等待线程

    public class ThreadTest15{
        private static Object obj = new Object();
        public static void main(String[] args){
            MyThread mt1 = new MyThread("t1");
            MyThread mt2 = new MyThread("t2");
            MyThread mt3 = new MyThread("t3");
            mt1.start();
            mt2.start();
            mt3.start();
            try{
                System.out.println(Thread.currentThread().getName() + " sleep 3s");
                Thread.sleep(3000);
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            synchronized(obj){
                System.out.println(Thread.currentThread().getName() + " notifyAll");
                obj.notifyAll();
            }
        }
        
        static class MyThread extends Thread{
            public MyThread(String name){
                super(name);
            }
            public void run(){
                synchronized(obj){
                    try{
                        System.out.println(Thread.currentThread().getName() + " waiting");
                        obj.wait();
                        System.out.println(Thread.currentThread().getName() + " continue");
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    //运行结果
    main sleep 3s
    t1 waiting
    t3 waiting
    t2 waiting
    main notifyAll
    t1 continue
    t2 continue
    t3 continue

    8. 定时器  

      定时器,间隔一定时间,执行指定程序,java.util.Timer定时器

    public class ThreadTest11{
        public static void main(String[] args) throws ParseException{
            Timer timer = new Timer();  //创建定时器
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
            Date date = sdf.parse("2021-03-21 21:18:20");
            timer.schedule(new LogTimer(),date,1000*10);    //每隔10s完成次数据备份
        }
    }
    
    class LogTimer extends TimerTask{
        public void run(){
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
            String nowtime = sdf.format(new Date());
            System.out.println(nowtime + "完成了一次数据备份");
        }
    }

    9. 实现线程的第三种方式

      实现callable接口,可以获取线程的返回值;

    public class ThreadTest12{
        public static void main(String[] args) throws ExecutionException, InterruptedException{
            FutureTask futuretask = new FutureTask(new Callable(){
                public Object call() throws Exception{
                    System.out.println("method begin");
                    Thread.sleep(1000*5);
                    System.out.println("method over");
                    int a = 100;
                    int b =200;
                    return a + b;
                }
            });
            
            Thread th = new Thread(futuretask);
            th.setName("tt");
            th.start();
            
            Object obj = futuretask.get();   //get()方法执行会使主线程进入阻塞状态,主线程必须等待子线程执行完成返回结果
            System.out.println("获取返回值: "+ obj);
        }
    }

      这种方式创建线程:

      优点:可以获取线程的返回值;

      缺点:必须等待子线程执行完得到返回结果后,才能执行主线程。

  • 相关阅读:
    Java帮助文档的生成
    Java内部类
    Java中利用标签跳出外层循环break
    【转】你真的了解word-wrap和word-break的区别吗?
    Office/Access 2013 扩展支持xbase/DBF 文件
    调用cmd.exe执行pdf的合并(pdftk.exe)
    input 数字输入控制(含小数)
    iis7.5 发布mvc出错的解决办法
    table中超过长度的列,显示省略号
    本地图片的预览和上传
  • 原文地址:https://www.cnblogs.com/homle/p/15146843.html
Copyright © 2011-2022 走看看