多线程基础(一)

1、程序、线程、进程的概念

2、多线程的两种实现方式

3、代理模式

4、线程的状态

=============================================================================================================================================================

程序、线程、进程的概念

程序:Program,是一个指令的集合

进程:Process,(正在执行中的程序)是一个静态的概念

          进程是程序的一次静态执行过程,占用特定的地址空间

          每个进程都是独立的,由3部分组成cpu、data、code

          缺点:内存浪费,cpu的负担

线程:是进程中一个“单一的连续控制流程”  (a single Thread, equential flow of control)/执行路径

           线程又被称为轻量级进程

           Threads run at the same time,independently of one another

           一个进程可拥有多个并行的(concurrent)线程

          一个进程中的线程共享相同的内存单元/内存地址空间--》可以访问相同的变量和对象,而且他们从同一堆中分配对象--》通信、数据交换、同步操作

         由于线程间的通信是在同一地址空间上进行的,所以不需要额外的通信机制,这就使得通信更简便而且信息传递的速度也更快

线程的两种实现方式:

方式一:用Thread实现
package com.test.ThreadTest;

public class ThreadDemo extends Thread{
    @Override
    public void run() {
       for(int i=0;i<10;i++){
           System.out.println(Thread.currentThread().getName()+"-----"+i);
       }
    }

    public static void main(String[] args) {
        ThreadDemo threadDemo = new ThreadDemo();
        threadDemo.start();
        for (int i =0;i<5;i++){
            System.out.println(Thread.currentThread().getName()+"====="+i);
        }
    }
}
方式二:用Runnable实现
package com.test.ThreadTest;

public class RunnableDemo implements Runnable {
    @Override
    public void run() {
        for (int i=0;i<10;i++){
            System.out.println(Thread.currentThread().getName()+"----"+i);
        }
    }

    public static void main(String[] args) {
        RunnableDemo runnableDemo = new RunnableDemo();
        Thread thread = new Thread(runnableDemo);//代理模式
        thread.start();
        for (int i=0;i<5;i++){
            System.out.println(Thread.currentThread().getName()+"===="+i);
        }
    }
}

实现多线程的时候:

   方式一:

        1、需要继承Thread类;

        2、必须要重写run方法,指的是核心执行的逻辑;

        3、线程在启动的时候,不要直接调用run方法,而是要通过start()来进行调用;

        4、每次运行相同的代码,出来的结果可能不一样,原因在于多线程谁先抢占资源无法进行人为控制;

   方式二:

         1、实现Runnable接口;

         2、重写run方法;

         3、创建Thread对象,将刚刚创建好的Runnable的子类实现类作为Thread的构造参数;

         4、通过thread.start()进行启动;

    两种方式比较:

         1、推荐第二种,java是单继承,一个类只能有一个父类,但是却可以实现多个接口,将继承关系留给最需要的类,所以第二种比第一种具有更好的扩展性

         2、使用Runnable接口之后不需要给共享变量添加static关键字,每次创建一个对象,作为共享对象即可

 Thread和Runnable多线程实例:

package com.test.ThreadTest;

public class ThreadsDemo extends Thread {

    private int ticket = 5;
    @Override
    public void run() {
        for (int i=0;i<100;i++){//不可能有100张票
            if(ticket>0){
                System.out.println(Thread.currentThread().getName()+"正在买票,此时还有"+(ticket--)+"张票");
            }
        }
    }

    public static void main(String[] args) {
        ThreadsDemo threadsDemo01 = new ThreadsDemo();
        ThreadsDemo threadsDemo02 = new ThreadsDemo();
        ThreadsDemo threadsDemo03 = new ThreadsDemo();
        ThreadsDemo threadsDemo04 = new ThreadsDemo();
        threadsDemo01.start();
        threadsDemo02.start();
        threadsDemo03.start();
        threadsDemo04.start();
    }
}

运行结果如下:因为每个线程都有属于自己的ticket

Thread-0正在买票,此时还有5张票
Thread-1正在买票,此时还有5张票
Thread-2正在买票,此时还有5张票
Thread-0正在买票,此时还有4张票
Thread-1正在买票,此时还有4张票
Thread-0正在买票,此时还有3张票
Thread-2正在买票,此时还有4张票
Thread-0正在买票,此时还有2张票
Thread-1正在买票,此时还有3张票
Thread-0正在买票,此时还有1张票
Thread-2正在买票,此时还有3张票
Thread-1正在买票,此时还有2张票
Thread-2正在买票,此时还有2张票
Thread-1正在买票,此时还有1张票
Thread-2正在买票,此时还有1张票
Thread-3正在买票,此时还有5张票
Thread-3正在买票,此时还有4张票
Thread-3正在买票,此时还有3张票
Thread-3正在买票,此时还有2张票
Thread-3正在买票,此时还有1张票

将ticket变量变成static之后的结果:依然有问题 

Thread-1正在买票,此时还有4张票
Thread-1正在买票,此时还有2张票
Thread-0正在买票,此时还有3张票
Thread-2正在买票,此时还有5张票
Thread-3正在买票,此时还有1张票       

接下来看Runnable的多线程实例:同样的逻辑

package com.test.ThreadTest;

public class RunnablesDemo implements Runnable {
    private int ticket = 5;//没有加static
    @Override
    public void run() {
        for(int i=0;i<100;i++){
            if(ticket>0){
                System.out.println(Thread.currentThread().getName()+"正在买票,此时还有"+(ticket--)+"张票");
            }
        }
    }

    public static void main(String[] args) {
        RunnablesDemo runnablesDemo = new RunnablesDemo();
        //多个thred是基于一个runnable建立的,共享Runnable对象上的资源,建议使用Runnable实现多线程
        Thread thread01 = new Thread(runnablesDemo);
        Thread thread02 = new Thread(runnablesDemo);
        Thread thread03 = new Thread(runnablesDemo);
        Thread thread04 = new Thread(runnablesDemo);
        thread01.start();
        thread02.start();
        thread03.start();
        thread04.start();
    }
}

运行结果:

Thread-0正在买票,此时还有5张票
Thread-2正在买票,此时还有3张票
Thread-2正在买票,此时还有2张票
Thread-2正在买票,此时还有1张票
Thread-1正在买票,此时还有4张票

 代理模式:

       实现Runnable创建线程时,用到了一个设计模式,代理模式,接下来简单说说代理模式(举个设计模式书中的例子,潘金莲西门庆的故事)

       都知道潘金莲是个美丽的女人,但是却嫁给了矮丑粗的武大郎,这个金莲每天看这个大郎实在是无语了,时间长了难免会yy,但是古代民风淳朴,自己不好办事,于是找了王婆作为代理;

先定义一种像金莲和王婆这种类型的人:

package com.test.ThreadTest.Proxy;

public interface KindWomen {

    public void makeEyesToMan();//抛媚眼

    public void playWithMan();//自己yy
}

潘金莲实现kindWomen:

package com.test.ThreadTest.Proxy;

public class PaoJinLian implements KindWomen {
    @Override
    public void makeEyesToMan() {
        System.out.println("潘金莲抛媚眼。。。");
    }

    @Override
    public void playWithMan() {
        System.out.println("潘金莲。。。。。");
    }
}

王婆虽然现在老了,但是年轻时候估计也是这方面的专家,所以很有经验,所以王婆肯定也具备KindWomen的特性,也知道金莲也是这种类型的,也能这么干;

package com.test.ThreadTest.Proxy;

public class WangPo implements KindWomen {
    private KindWomen kindWomen;
    public WangPo(){
        kindWomen = new PaoJinLian();
    }

    public WangPo(KindWomen kindWomen){
        this.kindWomen = kindWomen;
    }

    @Override
    public void makeEyesToMan() {
        kindWomen.makeEyesToMan();
    }

    @Override
    public void playWithMan() {
        kindWomen.playWithMan();
    }
}

王婆找到了西门庆;

package com.test.ThreadTest.Proxy;

public class XiMenQing {
    public static void main(String[] args) {
        WangPo wangPo = new WangPo();//用的无参构造器,王婆找到了西门庆,但是实际上是金莲跟西门庆。。。。。
        wangPo.makeEyesToMan();
        wangPo.playWithMan();
    }
}

里面还有一个贾氏,她跟金莲也是一类人,于是贾氏也找王婆做代理,也想让王婆帮他找西门庆;

package com.test.ThreadTest.Proxy;

public class JiaShi implements KindWomen {
    @Override
    public void makeEyesToMan() {
        System.out.println("贾氏抛媚眼。。。");
    }

    @Override
    public void playWithMan() {
        System.out.println("贾氏。。。。。");
    }
}

王婆也喜欢助人为乐,找到了西门庆,于是。。。。

package com.test.ThreadTest.Proxy;

public class XiMenQing {
    public static void main(String[] args) {
        JiaShi jiaShi = new JiaShi();//定义出来贾氏
        WangPo wangPo = new WangPo(jiaShi);//王婆把贾氏介绍给西门庆,此时是贾氏跟西门庆。。。。。。。
        wangPo.makeEyesToMan();
        wangPo.playWithMan();
    }
}

简单说一下代理模式,以后会在设计模块专栏细说。。。。。。

线程的状态

      线程的五种状态:新生、就绪、运行、死亡、阻塞

线程的生命周期:

      新生状态:

             当创建好当前线程对象之后,没有启动之前(没有调用start()前)eg:             

                  ThreadDemo threadDemo = new ThreadDemo;

                  RunnableDemo runnableDemo = new RunnableDemo();

       就绪状态:准备开始执行,并没有执行,调用start()之后

             当对应的线程创建完成,切调用start方法之后,所有的线程会添加到一个就绪队列,所有的线程同时去抢占cpu的资源;

        运行状态:当当前进程获取到cpu资源之后,就绪队列中的所有线程回去抢占cpu的资源,谁先抢占到谁先执行,在执行的过程中就叫做运行状态;

              抢占到cpu资源,执行代码逻辑开始

        死亡状态:当运行中的线程正常执行完所有的代码逻辑或者因为异常情况导致程序结束叫做死亡状态;

              进入的方式:

                       1、正常执行完成且结束;

                       2、人为终端执行,比如使用stop方法;

                       3、程序抛出未捕获异常;

         阻塞状态:在程序运行过程中,发生某些异常情况 ,导致当前线程无法在顺利执行下去,此时会进入阻塞状态,进入祖册状态的原因消除之后,

               所有的阻塞队列会再次进入到就绪状态中,随机抢占cpu资源,等待执行;

                进入的方式:

                       1、执行了sleep方法;

                       2、等待IO资源;

待更新。。。。。。

             

原文地址:https://www.cnblogs.com/bentuzi/p/12763242.html