【Java分析】java多线程(1、定义,创建线程)

进程是资源分配的最小单位,线程是CPU调度的最小单位

1、进程: 运行起来的程序。

            进程通信:网络连接,管道(铁路),信号量,共享内存+同步机制(锁)

            进程是应用程序运行的载体。一旦程序被载入到内存中并准备执行,它就是一个进程。进程是一种抽象的概念,进程是资源分配的基本单位,又是调度运行的基本单位,是系统中的并发执行的单位。

            进程是拥有资源和独立运行的最小单位,也是程序执行的最小单位。任务调度采用的是时间片轮转的抢占式调度方式,而进程是任务调度的最小单位,每个进程有各自独立的一块内存(地址空间),使得各个进程之间内存地址相互隔离。

            (1)进程一般由程序,数据集合和进程控制块三部分组成:

                      程序:用于描述进程要完成的功能,是控制进程执行的指令集;

                      数据集合:是程序在执行时所需要的数据和工作区;

                      程序控制块:包含进程的描述信息和控制信息是进程存在的唯一标志

           (2)进程具有的特征:

                      动态性:进程是程序的一次执行过程,是临时的,有生命期的,是动态产生,动态消亡的;

                      并发性:任何进程都可以同其他进行一起并发执行;

                      独立性:进程是系统进行资源分配和调度的一个独立单位;

                      结构性:进程由程序,数据和进程控制块三部分组成

           (3)进程状态转化图:

 

 

2、线程 : 单个进程中执行中每个任务就是一个线程 , 线程是进程中执行运算的最小单位。

            1、组成进程的个体

            2、cpu运行基本单位

            3、线程只是进程的一个入口,线程共享进程中的资源。

            4、局部变量线程私有的,栈(方法),程序计数器(记录下一条要执行的指令)

            5、通信:共享变量(可以是mysql 文件 全局变量)+同步机制(锁)

            随着计算机的发展,对CPU的要求越来越高,进程之间的切换开销较大,已经无法满足越来越复杂的程序的要求了。于是就发明了线程,线程是程序执行中一个单一的顺序控制流程,是程序执行流的最小单元,是处理器调度和分派的基本单位。一个进程可以有一个或多个线程,各个线程之间共享程序的内存空间(也就是所在进程的内存空间)。一个标准的线程由线程ID,当前指令指针PC,寄存器和堆栈组成。而进程由内存空间(代码,数据,进程空间,打开的文件)和一个或多个线程组成。

 

3、进程和线程区别联系:

           (1)进程和线程的关系:

                      1、一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。

                      2、资源分配给进程,同一进程的所有线程共享该进程的所有资源。

                      ​​​​​​3、CPU分给线程,即真正在CPU上运行的是线程。

           (2)进程与线程的区别

                      1. 线程是程序执行的最小单位,而进程是操作系统分配资源的最小单位;

                      ​​​​​​​2. 一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线

                      ​​​​​​​3. 进程之间相互独立,但同一进程下的各个线程之间共享程序的内存空间(包括代码段,数据集,堆等)及一些进程级的资源(如打开文件和信号等),某进程内的线程在其他进程不可见;

                      ​​​​​​​4. 调度和切换:线程上下文切换比进程上下文切换要快得多

           (3)进程和线程的区别

                      ​​​​​​​1、划分尺度:线程更小,所以多线程程序并发性更高;

                      ​​​​​​​2、资源分配&处理器调度:进程是资源分配的基本单位,线程是处理器调度的基本单位。  

                      ​​​​​​​3、地址空间:进程拥有独立的地址空间;线程没有独立的地址空间,同一进程内多个线程共享其资源;

                      ​​​​​​​4、执行:每个线程都有一个程序运行的入口,顺序执行序列和程序的出口,但线程不能单独执行,必须组成进程,一个进程至少有一个主线程。简而言之,一个程序至少有一个进程,一个进程至少有一个线程。

           (4)进程和程序区别

                      ​​​​​​​1、进程是一个动态概念,程序是静态概念。进程 存在于程序的执行过程中。

                      ​​​​​​​2、进程具有并发特性,程序没有。

                      ​​​​​​​3、进程间相互制约,而程序没有。资源的共享和竞争造成进程相互制约。

                      ​​​​​​​4、进程与程序之间不是一对一关系。

           一个程序执行在不同的数据集上就成为不同的进程,可以用进程控制块来唯一地标识每个进程。一个进程肯定有一个与之对应的程序,而且只有一个。而一个程序有可能没有与之对应的进程**(因为它没有执行),也有可能有多个进程与之对应(运行在几个不同的数据集上)。

4、并发与并行:

5、为何不使用多进程而是使用多线程?

           线程廉价,线程启动比较快,退出比较快,对系统资源的冲击也比较小。而且线程彼此分享了大部分核心对象(File Handle)的拥有权

           如果使用多重进程,但是不可预期,且测试困难

           1)需要频繁创建销毁的优先用线程

                    原因请看上面的对比。这种原则最常见的应用就是Web服务器了,来一个连 接建立一个线程,断了就销毁线程,要是用进程,创建和销毁的代价是很难承受的

           2)需要进行大量计算的优先使用线程

                    所谓大量计算,当然就是要耗费很多CPU,切换频繁了,这种情况下线程是最合适的。这种原则最常见的是图像处理、算法处理。

           3)强相关的处理用线程,弱相关的处理用进程

                    什么叫强相关、弱相关?理论上很难定义,给个简单的例子就明白了。一般的Server需要完成如下任务:消息收发、消息处理。“消息收发”和“消息处理”就是弱相关的任务,而“消息处理”里面可能又分为“消息解码”、“业务处理”,这两个任务相对来说相关性就要强多了。因此“消息收发”和“消息处理”可以分进程设计,“消息解码”、“业务处理”可以分线程设计。当然这种划分方式不是一成不变的,也可以根据实际情况进行调整。

           4)可能要扩展到多机分布的用进程,多核分布的用线程

                    原因请看上面对比。

           5)都满足需求的情况下,用你最熟悉、最拿手的方式

                    至于“数据共享、同步”、“编程、调试”、“可靠性”这几个维度的所谓的“复杂、简单”应该怎么取舍,我只能说:没有明确的选择方法。但我可以告诉你一个选择原则:如果多进程和多线程都能够满足要求,那么选择你最熟悉、最拿手的那个。需要提醒的是:虽然我给了这么多的选择原则,但实际应用中基本上都是“进程+线程”的结合方式,千万不要真的陷入一种非此即彼的误区。

 

6、java创建线程

              主线程:main

              子线程:创建方法有四

(1):继承Thread类 不能再继承别的类 重写run()方法

class MyThreadTest extends Thread{
    @Override
    public void run() {
        super.run();
        System.out.println("MyThread: "+Thread.currentThread().getName());
    }
}
public class MyThread {
    public static void main(String[] args) {
        MyThreadTest myThreadTest1 = new MyThreadTest();
//        myThreadTest.setName("oo7:");//定义线程名字
//        myThreadTest.start();//调用start方法才算是真正开启一个线程,
//        myThreadTest.run();// 调用run意思是运行了一个普通类里的方法。
        System.out.println(myThreadTest1.currentThread().getName());
        for (int i = 0; i < 100; i++) {
            MyThreadTest myThreadTest = new MyThreadTest();
            myThreadTest.setName("nihao-"+i);
            myThreadTest.start();
        }//会被线程池代替
        System.out.println(myThreadTest1.currentThread().getName());
    }
}

(2):实现Runnable接口 可以继承别的类和接口 重写run()方法

class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println("Thread :" + Thread.currentThread().getName());
    }
}
public class MyRunnableDemo {
    public static void main(String[] args) {
        MyRunnable runnable = new MyRunnable();
        Thread t = new Thread(runnable,"pipip-");
        t.start();
        t.run();
    }
}

 

(3):实现Callable接口 重写call()方法,有返回值

class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        System.out.println("Thread :"+Thread.currentThread().getName());
        return 1;
    }
}
public class MyCallAbleDemo {
    public static void main(String[] args) {
        MyCallable callable = new MyCallable();
        FutureTask<Integer> task = new FutureTask<Integer>(callable);
        //task 是为了获取返回值
        Thread t = new Thread(task);
        t.start();
        try {
            Integer i = task.get();
            System.out.println("i = " +i);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

(4)线程池

7、run和start方法区别

          start() 方法:

                    1、启动线程

                    2、使线程状态从NEW变成RUNNABLE状态。

                    3、内部调用Runnable接口的run()方法。

          run() 方法:

                    run()方法是Runnable接口的一个抽象方法,由java虚拟机直接调用的,不会创建的新线程。

          区别:

                    1、定义的地点不一样:

                              start()方法在java.lang.Thread类中定义,而 run()方法在java.lang.Runnable接口中定义,必须在实现类中重写。

                    2、 当程序调用start()方法时,会创建一个新线程,然后执行run()方法。

                           当直接调用run()方法,则不会创建新的线程,run()方法将作为当前调用线程本身的常规方法调用执行,并且不会发生多线程(Thread.currentThread().getName())打印结果为main)。

                    3、start()方法不能多次调用,否则抛出java.lang.IllegalStateException,而run()方法可以进行多次调用,因为它只是一种正常的方法调用。

8、三种实现方式的区别

           1、Callable和Runnable最后都是调用Thread的start方法启动。

           2、使用Thread是继承他的类,这样就不能继承别的类了(单继承),而用runnable和callabe是实现接口,这样更灵活。

           3、callable是重写call()方法,而且他有返回值

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值