码迷,mamicode.com
首页 > 编程语言 > 详细

多线程(一)

时间:2017-09-30 00:34:22      阅读:255      评论:0      收藏:0      [点我收藏+]

标签:提高   时间段   alt   路径   nal   call   java虚拟机   重写   好处   

1 进程

  • 进程:
    • 正在运行中的程序,是系统进行资源分配和调用的独立单位。
    • 每一个进程独有它自己的内存空间和系统资源。

 

  • 多进程的意义:
    • 单进程计算机只能做一件事情,而我们现在的计算机都可以一边玩游戏,一边听音乐,所以我们常见的操作系统都是多进程操作系统。比如Linux和Mac等,能在同一段时间内执行多个任务。
    • 对于单核计算机而言,游戏进程和听音乐进程是同时运行的,当然不是,因为CPU在某个时间点上只能做一件事情,计算机是在游戏进程和听音乐进程间做频繁切换,且切换速度很快,所以,我们感觉游戏和音乐是同时进行的,其实并不是同时进行的。
    • 多进程的作用不是提高执行速度,而是为了提高CPU的使用效率。  

 

2 线程

  • 线程是进程中的单个顺序控制流,是一条执行路径。或者换句话说,一个进程内部可以执行多个任务,而每一个任务我们都可以看成是一个线程。
  • 一个进程如果只有一条执行路径,就称为单线程程序。
  • 一个进程如果有多条执行路径,就称为多线程程序。

 

3 多线程存在的意义

  • 多线程的作用不是为了提高CPU的使用效率,而是为了提高应用程序的使用效率。
  • 多线程给我们的错觉就是让我们认为多个线程是并发执行的,其实不然,因为多个线程是共享一个进程的资源(堆内存和方法区),但是栈内存是独立的,一个线程一个栈,所以他们仍然是在抢CPU的资源执行。一个时间点上只有一个线程执行,而且谁抢到,不一定,所以,造成了线程运行的随机性。

 

  • 并发:是一个时间段同时运行多个程序。
  • 并行:是一个时间点上同时运行多个程序。

 

4 java程序的运行原理

  • java命令会启动java虚拟机,启动JVM,等于启动了一个应用程序,也就是启动了一个进程。该进程会自动启动一个“主线程”,然后主线程去调用某个类的main方法,所以main方法运行在主线程中。但是JVM启动还会启动垃圾回收线程,所以java程序是多线程的。

 

  • 验证:垃圾回收线程
package java012;

/**
 * 2017/9/29
 * 说明:
 */
class Demo {
    public void finalize(){
        System.out.println("我要死了");
    }
}
public class ThreadDemo {
    public static void main(String[] args) {
        new Demo();
        new Demo();
        System.gc();
        new Demo();
        System.out.println("你好世界");
    }
}

技术分享

 

5 多线程的好处和弊端

  • 好处:“适当”提高程序的执行效率、“适当”提高CPU和内存的利用率、线程执行完成后会自动销毁节省内存。
  • 弊端:每开启一条线程就会占用一定内存空间,降低程序性能;线程越多,CPU调度(多个线程之间切换)开销越大,时间开销、空间开销。

 

 

6  线程的创建方式一-

  •  创建线程的步骤:
    • ①定义一个类继承Thread类
    • ②覆盖Thread类中的run方法
    • ③创建Thread类的子类对象  
    • ④调用start()方法,启动线程并调用自定义线程的run()方法

 

  •  解释为什么创建线程需要继承Thread,并重写run方法。
    • 创建线程的目的是为了开启一条执行路径,去运行指定的代码和其他代码并发运行。而运行指定的代码就是这个执行路径的任务。JVM创建的主线程的任务都是定义在main方法中, 那么自定义的线程的任务在哪里你?Thread类用于描述线程,线程需要任务的,所以Thread提供了对任务的描述,这个任务就是Thread类的run方法来体现的,也就是说,run方法就是封装自定义线程运行任务的函数。那么此时你可能会想,我们直接new Thread().run()方法不就可以了,那么非常抱歉,此时,运行的不是我需要并发执行的代码,而是Thread类中的run()方法中的代码,可惜的是,不是我要的,所以,这就是为什么在java中,我们创建线程需要继承Thread类,并重写run()方法的原因。 

 

  •  示例:创建线程
package java012;

/**
 * 2017/9/29
 * 说明:
 */
class Demo extends Thread {
    private String name;
    public Demo(String name){
        this.name = name;
    }

    public void run(){
        this.show();
    }

    public void show(){
        for(int x =0;x<100;x++){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(name+":"+x);
        }
    }

}
public class ThreadDemo {
    public static void main(String[] args) {
        Demo d1 = new Demo("d1");
        Demo d2 = new Demo("d2");
        d1.start();
        d2.start();
    }
}

 

 6.1 线程的一些方法

  •  返回该线程的名称
public final String getName()
package java012;

/**
 * 2017/9/29
 * 说明:
 */
class Demo extends Thread {
    private String name;
    public Demo(String name){
        this.name = name;
    }

    public void run(){
        this.show();
    }

    public void show(){
        for(int x =0;x<10;x++){
            System.out.println(name+":"+x+":线程的名称:"+getName());
        }
    }

}
public class ThreadDemo {
    public static void main(String[] args) {
        Demo d1 = new Demo("d1");
        Demo d2 = new Demo("d2");
        d1.run();
        d2.run();
    }
}

技术分享

结果好像不对,因为我们并没有调用start()方法,那么此时运行的打印的线程的名称应该是main之类的。对,应该打印的是main之类的,但是,我们要知道,我们调用的是Thread的无参构造方法。代码如下所示: 

package java012;

/**
 * 2017/9/29
 * 说明:
 */
class Demo extends Thread {
    private String name;
    public Demo(String name){
        super();//调用父类的无参构造方法
        this.name = name;
    }

    public void run(){
        this.show();
    }

    public void show(){
        for(int x =0;x<10;x++){
            System.out.println(name+":"+x+":线程的名称:"+getName());
        }
    }

}
public class ThreadDemo {
    public static void main(String[] args) {
        Demo d1 = new Demo("d1");
        Demo d2 = new Demo("d2");
        d1.run();
        d2.run();
    }
}

那么,此时我们观察Thread的源码就可以知道答案:

/**
     * Allocates a new {@code Thread} object. This constructor has the same
     * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
     * {@code (null, null, gname)}, where {@code gname} is a newly generated
     * name. Automatically generated names are of the form
     * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
     */
    public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }

这下知道原因了吧。

  • 返回对当前正在执行的线程的引用。
public static Thread currentThread()
package java012;

/**
 * 2017/9/29
 * 说明:
 */
class Demo extends Thread {
    private String name;
    public Demo(String name){
        super();//调用父类的无参构造方法
        this.name = name;
    }

    public void run(){
        this.show();
    }

    public void show(){
        for(int x =0;x<10;x++){
            System.out.println(name+":"+x+":线程的名称:"+Thread.currentThread().getName());
        }
    }

}
public class ThreadDemo {
    public static void main(String[] args) {
        Demo d1 = new Demo("d1");
        Demo d2 = new Demo("d2");
        d1.run();
        d2.run();
    }
}

技术分享

上面的代码证明了2点:①如果我们不调用自定义线程的start()方法,就不是开启新的线程②想获取运行时的线程,必须通过Thread.currentThread()。

package java012;

/**
 * 2017/9/29
 * 说明:
 */
class Demo extends Thread {
    private String name;
    public Demo(String name){
        super();//调用父类的无参构造方法
        this.name = name;
    }

    public void run(){
        this.show();
    }

    public void show(){
        for(int x =0;x<10;x++){
            System.out.println(name+":"+x+":线程的名称:"+Thread.currentThread().getName());
        }
    }

}
public class ThreadDemo {
    public static void main(String[] args) {
        Demo d1 = new Demo("d1");
        Demo d2 = new Demo("d2");
        d1.start();
        d2.start();
        System.out.println("主线程的名字:"+Thread.currentThread().getName());
    }
}

技术分享

  • 给线程取有意义的名称,而不是默认的。
public Thread(String name)
package java012;

/**
 * 2017/9/29
 * 说明:
 */
class Demo extends Thread {
    private String name;
    public Demo(String name){
        super(name);//调用父类的有参构造方法,给线程取定义的名称
        this.name = name;
    }

    public void run(){
        this.show();
    }

    public void show(){
        for(int x =0;x<10;x++){
            System.out.println(name+":"+x+":线程的名称:"+Thread.currentThread().getName());
        }
    }

}
public class ThreadDemo {
    public static void main(String[] args) {
        Demo d1 = new Demo("d1");
        Demo d2 = new Demo("d2");
        d1.start();
        d2.start();
        System.out.println("主线程的名字:"+Thread.currentThread().getName());
    }
}

技术分享

 

多线程(一)

标签:提高   时间段   alt   路径   nal   call   java虚拟机   重写   好处   

原文地址:http://www.cnblogs.com/xuweiweiwoaini/p/7612585.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!