zoukankan      html  css  js  c++  java
  • 廖雪峰的多线程 3 回顾 这些都是基础的

    创建新线程
    Java语言内置了多线程支持。当Java程序启动的时候,实际上是启动了一个JVM进程,然后,JVM启动主线程来执行main()方法。在main()方法中,我们又可以启动其他线程。
    要创建一个新线程非常容易,我们需要实例化一个Thread实例,然后调用它的start()方法:

    public class Main {
        public static void main(String[] args) {
            Thread t = new Thread();
            t.start(); // 启动新线程
        }
    }
    
    

    但是这个线程启动后实际上什么也不做就立刻结束了。我们希望新线程能执行指定的代码,有以下几种方法:
    方法一:从Thread派生一个自定义类,然后覆写run()方法:

    public class Main {
        public static void main(String[] args) {
            Thread t = new MyThread();
            t.start(); // 启动新线程
        }
    }
    
    class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println("start new thread!");
        }
    }
    
    

    或者下面这样

    package 线程学习pn;
    /**
    * 
    * @author SeeClanUkyo
    *
    */
    class MyThread implements Runnable {
    
     public static long minPrime;
     boolean isPrime;
     int count = 0;
     public void run() {
      
       while (true) {
        try {
         Thread.sleep(1000 * 1);
         System.out.println("-----------------扫描质数中");
        } catch (InterruptedException e) {
         e.printStackTrace();
        }
        
        synchronized (this) {
        
        isPrime = false;
        count = 0;
        minPrime++;
        if(minPrime>1) {
         //如果++后的minPrime
         // 质数
         for (int i = 2; i <= Math.sqrt(minPrime); i++) {
          if (minPrime % i == 0) { // 
           count++;// 结束后 为0 则为质数
           break;
          }
         }
         if (count == 0) {
          isPrime = true;
         }
         
         if (isPrime) {
          System.out.println(Thread.currentThread().getName() + ":  " + minPrime);
         }
        }
        
       }
        
      }
     }
    
    }
    
    public class ThreadTest02 extends MyThread{
    
     public static void main(String[] args) throws InterruptedException {
    
      Runnable r = new MyThread();
    
      //测试是否线程越多,获得的质数越多
                    //加大线程!看看是否扫描得更快!结果是一定的!多线程的魅力!
    
      for(long i=0;i<9999;i++) { 
       new Thread(r).start();
      }
      
    
      /*
       * 嚼6次口香糖的时间内:
       * 9个线程找到最大质数 53
       * 99个线程找到最大质数593
       * 999个线程找到最大质数5107
       * 9999个线程找到最大质数33413
       * 
       * 有时会抛出一下错误:
       * Failed to start thread - _beginthreadex failed (EACCES) for attributes: stacksize: default, flags: CREATE_SUSPENDED STACK_SIZE_PARAM_IS.
       * Exception in thread "main" 
       */
     }
    }
    

    执行上述代码,注意到start()方法会在内部自动调用实例的run()方法。
    方法二:创建Thread实例时,传入一个Runnable实例:

    public class Main {
        public static void main(String[] args) {
            Thread t = new Thread(new MyRunnable());
            t.start(); // 启动新线程
        }
    }
    
    class MyRunnable implements Runnable {
        @Override
        public void run() {
            System.out.println("start new thread!");
        }
    }
    

    package 线程学习pn;
    
    public class ThreadTest02 extends Thread {
    
     public static void main(String[] args) throws InterruptedException {
    
      Thread test02 = new ThreadTest02(233);
      new ThreadTest02(2).start();
      
      boolean isPrime;
      int count = 0;
      
      while(true) {
       System.out.println("Thread.sleep(1000*4)");
       Thread.sleep(1000*4);
       isPrime = false;
       count = 0;
       minPrime++;
       // 质数
       for (int i = 2; i <= Math.sqrt(minPrime); i++) {
        if (minPrime % i == 0) { //233%2  
         count++;//结束后 为0 则为质数
         break;
        }
       }
       if (count == 0) {
        isPrime = true;
       }
       if (isPrime) {
        System.out.println(minPrime+"--> MainTread");
       }
      }
      
     }
    
     static long minPrime;
    
     ThreadTest02(long minPrime) {
      this.minPrime = minPrime;
     }
    
     
    
     public void run() {
    
      
      boolean isPrime;
      int count = 0;
      while(true) {
       System.out.println("new ThreadTest02(2).sleep(1000*5)");
       try {
        Thread.sleep(1000*5);
       } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
       }
       isPrime = false;
       count = 0;
       minPrime++;
       // 质数
       for (int i = 2; i <= Math.sqrt(minPrime); i++) {
        if (minPrime % i == 0) { //233%2  
         count++;//结束后 为0 则为质数
         break;
        }
       }
       if (count == 0) {
        isPrime = true;
       }
       if (isPrime) {
        System.out.println(minPrime+"--> new ThreadTest02(2) Tread ");
       }
      }
      
    
     }
    
    }
    

    或者用Java8引入的lambda语法进一步简写为:

    public class Main {
        public static void main(String[] args) {
            Thread t = new Thread(() -> {
                System.out.println("start new thread!");
            });
            t.start(); // 启动新线程
        }
    }
    
    

    有童鞋会问,使用线程执行的打印语句,和直接在main()方法执行有区别吗?
    区别大了去了。我们看以下代码:

    public class Main {
        public static void main(String[] args) {
            System.out.println("main start...");
            Thread t = new Thread() {
                public void run() {
                    System.out.println("thread run...");
                    System.out.println("thread end.");
                }
            };
            t.start();
            System.out.println("main end...");
        }
    }
    

    我们用蓝色表示主线程,也就是main线程,main线程执行的代码有4行,首先打印main start,然后创建Thread对象,紧接着调用start()启动新线程。当start()方法被调用时,JVM就创建了一个新线程,我们通过实例变量t来表示这个新线程对象,并开始执行。
    接着,main线程继续执行打印main end语句,而t线程在main线程执行的同时会并发执行,打印thread run和thread end语句。
    当run()方法结束时,新线程就结束了。而main()方法结束时,主线程也结束了。
    我们再来看线程的执行顺序:

    main线程肯定是先打印main start,再打印main end;
    t线程肯定是先打印thread run,再打印thread end。
    

    但是,除了可以肯定,main start会先打印外,main end打印在thread run之前、thread end之后或者之间,都无法确定。因为从t线程开始运行以后,两个线程就开始同时运行了,并且由操作系统调度,程序本身无法确定线程的调度顺序。
    要模拟并发执行的效果,我们可以在线程中调用Thread.sleep(),强迫当前线程暂停一段时间:

    public class Main {
        public static void main(String[] args) {
            System.out.println("main start...");
            Thread t = new Thread() {
                public void run() {
                    System.out.println("thread run...");
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {}
                    System.out.println("thread end.");
                }
            };
            t.start();
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {}
            System.out.println("main end...");
        }
    }
    

    sleep()传入的参数是毫秒。调整暂停时间的大小,我们可以看到main线程和t线程执行的先后顺序。
    要特别注意:直接调用Thread实例的run()方法是无效的:

    public class Main {
        public static void main(String[] args) {
            Thread t = new MyThread();
            t.run();
        }
    }
    
    class MyThread extends Thread {
        public void run() {
            System.out.println("hello");
        }
    }
    

    直接调用run()方法,相当于调用了一个普通的Java方法,当前线程并没有任何改变,也不会启动新线程。上述代码实际上是在main()方法内部又调用了run()方法,打印hello语句是在main线程中执行的,没有任何新线程被创建。
    必须调用Thread实例的start()方法才能启动新线程,如果我们查看Thread类的源代码,会看到start()方法内部调用了一个private native void start0()方法,native修饰符表示这个方法是由JVM虚拟机内部的C代码实现的,不是由Java代码实现的。

    线程的优先级
    可以对线程设定优先级,设定优先级的方法是:

    Thread.setPriority(int n) // 1~10, 默认值5
    

    优先级高的线程被操作系统调度的优先级较高,操作系统对高优先级线程可能调度更频繁,但我们决不能通过设置优先级来确保高优先级的线程一定会先执行。

    上午10:30有电话面试

  • 相关阅读:
    圆形按钮窗口控制-不断减少的圆圈
    图像按钮和模拟Windows媒体播放器UI
    圆形按钮
    本机Win32主题感知所有者绘制控件没有MFC
    CRegionButton -一个多向按钮
    Iconits
    CxShadeButton
    管道符 |
    gedit
    more/less
  • 原文地址:https://www.cnblogs.com/ukzq/p/13413225.html
Copyright © 2011-2022 走看看