zoukankan      html  css  js  c++  java
  • Java多线程详解(一)

    Java----多线程详解

           多线程是Java基础知识的最后一部分,同样也是Java学习中的一个难点。在学习多线程时,深刻理解它的思想是非常必要的,在有了多线程的思想后,学习多线程的语法和规则就会很容易。

    1、多线程简介

           多线程是现代操作系统的发展方向,所以Java肯定是支持多线程的,它具有并发性、执行效率高的特点。多线程是实现并发的一种有效手段,一个进程可以通过运行多个线程来并发地执行多项任务,而多个线程之间的调度执行是由系统来实现的。

           进程是一个执行的程序,多进程的多任务处理的特点是允许计算机同时运行两个或多个程序。它也是一次动态的执行过程,指的是从代码加载、执行到执行结束的一个完整过程。

           线程是比进程小的执行单位,进程的每个小部分都由线程来管理。多线程程序比多进程程序需要更少的“管理费用”。线程共享相同的地址空间并且共同分享同一个进程,这可以使及其节省大量的CPU利用空间,从而能CPU能执行更多的任务。

           下面先看一个使用多线程的示例程序:

    public class test{

        ThreadUseExtends tue = newThreadUseExtends();

        public static void main(String[] str) {

            //主线程

            test t = new test();

            t.tue.start();//启动线程

            try {

                Thread.sleep(1000);//主线程挂起1秒

            } catch (Exception e) {

                return;

            }

        }

       

        public void PrintA() {

            for (int i = 0; i < 10; i++) {

                System.out.println(i +"");

            }

        }

       

        public void PrintB() {

            for (int i = 10; i < 20; i++) {

                System.out.println(i +"");

            }

        }

       

        class ThreadUseExtends extends Thread{

            @Override

            public void run() {

                PrintA();

                System.out.println();

                try {

                    for (int i = 0; i < 10; i++){

                        sleep(1000);//线程挂起1秒

                       System.out.print("*");

                    }

                    System.out.println();

                    PrintB();

                } catch (Exception e) {

                    System.err.println(e);

                }

            }

        }

    }

    2、如何创建线程

           线程的创建包括主线程的创建、实现Runnable接口创建和继承Thread类的创建。

           1)、主线程的创建

           程序的主线程在程序启动执行时立刻运行,它是所有的线程中最早运行的线程,还是产生其他子线程的线程,同时由于它要执行各种关闭动作,又是最后完成的线程。主线程是在程序启动时自动创建的,但它也是可以由Thread对象控制的。可以通过Thread对象调用currentThread()方法获得一个主线程的引用。获得主线程的引用后,就可以像控制其他线程那样控制主线程了。下面是一个示例:

    public static voidmain(String[] str) {

            //获得主线程的引用

            Thread t = Thread.currentThread();

            System.out.println("主线程:" + t);

            t.setName("我的主线程");

            System.out.println("改变名称后:" + t);

            //线程内容

            try {

                for (int i = 0; i < 5; i++) {

                    System.out.println(i);

                    t.sleep(1000);

                }

            } catch (Exception e) {

                e.printStackTrace();

            }

        }

           t作为语句println()中参数运用时输出的结果,它的顺序为:线程名称、优先级和组的名称。

           2)、实现Runnable接口

           创建一个线程有两个方法:实现Runnable接口;进程Thread类。创建线程最简单的方法就是创建一个实现Runnable接口的类,Runnable抽象了一个执行代码单元。可以通过实现Runnable接口的方法创建每一个对象的线程。实现Runnable接口的类,需要定义一个名为run()的无参数方法。

           实现了Runnable类不需要是Thread的子类就可以运行,只需要实例化一个Thread对象,并把自己的引用当作参数传递给Thread的构造方法即可。

           每个执行线程开始都作为Thread类的一个实例,无论是在哪种创建线程的方法中。首先需要实例化Runnable类:

                  MyRunnable r = newMyRunnable();

           然后即可引用Runnable类实例化线程:

                  Thread t = new MyRunnable();

           下面是一个通过实现Runnable接口来创建线程的实例:

    public class test{

        public static void main(String[] str) {

            //实例化一个线程

            MyThread r = new MyThread();

            Thread t = new Thread(r);

            t.setPriority(5);//设置线程的优先级

            t.start();//对run方法进行调用

            //主程序内容

            try {

                for (int i = 0; i < 10; i++) {

                   System.out.println("b");

                    Thread.sleep(1000);

                }

            } catch (Exception e) {

            }

            

        }

    }

    //通过实现Runnable接口创建线程

    class MyThread implementsRunnable{

        int i;

        @Override

        public void run() {

            try {

                while (true) {           

                   System.out.println("a" + i++);

                    Thread.sleep(1000);

                    if (i == 10) break;

                }   

            } catch (Exception e) {

            }

        }

    }

           请仔细研究这段代码,并多次调试观察打印出来的内容,你会有更好滴理解线程的概念和多线程执行的先后顺序。

           3)、通过继承Thread类创建线程

           Java中创建给管理线程的虚拟CPU是java.lang.Thread类的一个实例。也可以说Thread类的对象就是一个运行代码和使用数据的虚拟CPU。多个Thread对象可以共享代码和数据。继承Thread类创建线程的方法为:创建一个新类来继承Thread类,然后再创建该类的实例。当一个类继承Thread时,它必须重载run()方法,在这里run()方法也是新线程的入口。另外它也必须调用start()方法启动新线程执行。下面是一个实例:

    public class test{

        public static void main(String[] str) {

            //实例化一个线程

            MyThread r = new MyThread();

            r.start();//对run()方法进行调用

            r.setPriority(5);//设置优先级

            try {

                for (int i = 0; i < 10; i++) {

                   System.err.println("b");

                    Thread.sleep(1000);

                }

            }catch (Exception e) {

            }

        }

    }

    //通过继承Thread创建线程

    class MyThread extends  Thread{

        int i;

        @Override

        public void run() {

            try {

                while (true) {           

                   System.out.println("a" + i++);

                    Thread.sleep(1000);

                    if (i == 10) break;

                }   

            } catch (Exception e) {

            }

        }

    }

           请将上面的实例跟通过实现Runnable接口创建线程的实例进行对比,通过代码对比和打印内容的对比,你将会发现这两种方法的区别以及各自的优缺点。

           4)、两种方法的比较

           Thread类定义了很多方法可以被它的子类重载,但是只有一个方法必须被重载,那就是run()方法。这个方法也是Runnable接口所必须的。因此如果不需要重载Thread的其他方法,选择实现Runnable接口创建线程的方法是最好的。

           5)、创建多线程

           前面值编写了单线程和双线程,下面来创建多线程。多线程可以为系统的内存分配做一个很好的处理,缓解内存的压力。下面是一个多线程的示例:

    public class test{

        public static void main(String[] str) {

            //创建3个线程

            MyThread1 t1 = new MyThread1("第1线程");

            MyThread2 t2 = new MyThread2("第2线程");

            MyThread3 t3 = new MyThread3("第3线程");

            t1.start();

            t2.start();

            t3.start();

        }

    }

     

    class MyThread1 extendsThread{

        String name;

        public MyThread1(String threadName) {

            name = threadName;

        }

        @Override

        public void run() {

            try {

                for (int i = 0; i < 10; i++) {

                    System.out.println(name +":" + i);

                    Thread.sleep(1000);

                }

            } catch (Exception e) {

            }

            System.err.println(name + "退出");

        }

    }

    class MyThread2 extendsThread{

        String name;

        public MyThread2(String threadName) {

            name = threadName;

        }

        @Override

        public void run() {

            try {

                for (int i = 0; i < 10; i++) {

                    System.out.println(name +":" + i);

                    Thread.sleep(1000);

                }

            } catch (Exception e) {

            }

            System.err.println(name + "退出");

        }

    }

    class MyThread3 extendsThread{

        String name;

        public MyThread3(String threadName) {

            name = threadName;

        }

        @Override

        public void run() {

            try {

                for (int i = 0; i < 10; i++) {

                    System.out.println(name +":" + i);

                    Thread.sleep(1000);

                }

            } catch (Exception e) {

            }

            System.err.println(name + "退出");

        }

    }

           如果你是个聪明的人,你肯定会问,为什么不只创建一个Thread类MyThread1,然后实例化3个MyThread1开始执行呢?这样做代码不就少了吗?这个问题涉及到线程的优先级和线程的并发执行,现在讲不容易理解,下面我会进行详细的讲解。

           在程序中用到了线程的构造器,在前面的程序中没有直接给出,而是应用的默认构造器。线程中的构造器很多,有如下几种:

           >  Thread()

           >  Thread(Runnable target)

           >  Thread(Runnable target ,String name)

           >  Thread(String name)

           >  Thread(ThreadGroup group ,Runnable target)

           >  Thread(ThreadGroup , group ,Runnable target , String name)

           >  Thread(ThreadGroup group ,String name)

           对线程进行操作时,其运行结果是不确定的,也就是说起运行结果有可能不一样。这就是之前我为什么让大家反复调试查看打印结果的原因。不过可以肯定的是每个线程都将启动,每个线程都运行完成。

     

  • 相关阅读:
    剑指offer——最小的K个数和数组中第K大的元素
    Leetcode刷题指南链接整理
    160. Intersection of Two Linked Lists
    100. Same Tree
    92. Reverse Linked List II
    94. Binary Tree Inorder Traversal
    79. Word Search
    78,90,Subsets,46,47,Permutations,39,40 DFS 大合集
    0x16 Tire之最大的异或对
    0x16 Tire
  • 原文地址:https://www.cnblogs.com/jiangu66/p/2997501.html
Copyright © 2011-2022 走看看