java 线程介绍

来源:互联网 发布:迪杰斯特拉算法 详解 编辑:程序博客网 时间:2024/06/07 10:38

java 中线程的状态


 线程一般分为抢占式和非抢占式

       抢占式是操作系统分配完cpu资源后,将定期的中断线程,将cpu资源分配给其他线程各个线程不能独占cpu资源

      非抢占式的线程独占cpu 除非自己主动让出cpu或者线程执行完毕,这样可能会导致一个线程执行时间长会导致其他线程饿死

      java jvm大多线程抢占式的(部分操作系统可能是非抢占式的我没听说过)

 

 

线程,进程,协程

     进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.

     线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.

      同一个进程中的多个线程之间可以并发执行.对进程而言,线程是一个更加接近于执行体的概念,它可以与同进程中的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。

    进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能线程,不能用进程。

1) 简而言之,一个程序至少有一个进程,一个进程至少有一个线程.

2) 线程的划分尺度小于进程,使得多线程程序的并发性高。

3) 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。

4) 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

5) 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

4.优缺点

线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。而进程则可以跨机器迁移

 

     协程产生的原因:目前sunjdk的实现中启动一个Thread 意味着启动一个运行一个原生线程当这个线程中有任何阻塞动作(例如同步文件IO  同步网络IO。锁等待,Thread.sleep等)线程会被挂起,但仍然占据线程资源        
协程:采用协程后,当线程等待执行阻塞后立即释放线程资源(java可以使用Kilim框架实现)

线程组的概念

    可以把线程归属到某一个线程组中,线程组中可以有线程对象,也可以有线程组,组中还可以有线程,这样的组织结构有点类似于树的形式:可以批量管理线程或线程组对象,有效地对线程或线程组对象进行组织。

Thread 源码分析

     registerNatives()native方法由c或c++实现,该方法主要的作用就是注册一些本地方法供 Thread 类使用,如 start0(),stop0() 等等,可以说,所有操作本地线程的本地方法都是由它注册的。

       构造方法 所有的构造方法走的都是以下函数 

 // ThreadGroup 表示线程组   Runnable 表示为运行的对象,name为线程名称, stackSize堆栈大小,AccessControlContext 为封装一个上下文 并对访问系统资源的校验

 privatevoidinit(ThreadGroup g, Runnable target, String name,

                      long stackSize,AccessControlContext acc) {

        if (name ==null) {

            throw new NullPointerException("name cannot benull");

        }

 

        this.name = name.toCharArray();

 

        Thread parent = currentThread();

        //拿到系统安全管理器

        SecurityManager security = System.getSecurityManager();

        if (g ==null) {

            /* Determine if it's an applet or not */

 

            /* If there is a security manager, ask the security manager

               what to do. */

            if (security !=null) {

                g = security.getThreadGroup();

            }

 

            /* If the security doesn't have a strong opinion of the matter

               use the parent thread group. */

            if (g ==null) {

                g = parent.getThreadGroup();

            }

        }

 

        /* checkAccess regardless of whether or not threadgroup is

           explicitly passed in. */

      //  确定当前运行的线程是否有权修改此线程组。

        g.checkAccess();

 

        /*

         * Do we have the required permissions?

         */安全检查

        if (security !=null) {

                        if (isCCLOverridden(getClass())) {

                                          security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);

            }

        }

 

        g.addUnstarted();

        //成员变量的赋值

        this.group = g;

        this.daemon = parent.isDaemon();

        this.priority = parent.getPriority();

        if (security ==null || isCCLOverridden(parent.getClass()))

            this.contextClassLoader = parent.getContextClassLoader();

        else

            this.contextClassLoader = parent.contextClassLoader;

        this.inheritedAccessControlContext =

                acc != null ? acc :AccessController.getContext();

        this.target = target;

        setPriority(priority);

         //继承的ThreadLocal复制ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个   //线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

        if (parent.inheritableThreadLocals !=null)

            this.inheritableThreadLocals =

                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);

        /* Stash the specified stack size in case the VM cares */

        this.stackSize = stackSize;

 

        /* Set thread ID */

        tid = nextThreadID();

   }

 

     start方法

  //状态为不是0为不是运行状态

 if(threadStatus!= 0)

            throw new IllegalThreadStateException();

 

        /* Notify the group that this thread is about to be started

         * so that it can be added to thegroup's list of threads

         * and the group's unstarted count canbe decremented. */

        group.add(this);

 

        boolean started =false;

        try {

            // native使线程变成可运行状态等待cpu调度 调度成功执行run方法

            start0();

            started = true;

        } finally {

              //没有启动成功的处理逻辑

            try {

                if (!started) {

                    group.threadStartFailed(this);

                }

            } catch (Throwable ignore) {

                /* do nothing. If start0 threw a Throwable then

                  it will be passed up the callstack */

            }

        }

   }

 

    run方法

    if (target !=null){

            target.run();

       }

 

java 实现多线程

 

1.继承Thread 类

package com.mq.test.Thread;

import java.util.concurrent.BrokenBarrierException;

import java.util.concurrent.CyclicBarrier;

 

public classTestThread extendsThread {

 

    private int i;

    private CyclicBarriercyclicbarrier;

    public TestThread(int i,CyclicBarriercyclicbarrier){

        this.i=i;

        this.cyclicbarrier=cyclicbarrier;

       

    }

    @Override

    public void run() {

        try {

            // cyclicbarrier 初始化一个资源数每次调用awaitawait的值就加一,当await没有达到初始值时阻塞,直到达到初始化值所有阻塞的线程被唤醒

            cyclicbarrier.await();

        }catch(InterruptedException| BrokenBarrierException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

        System.out.println("我是第"+i+"线程");

    }

 

    public static void main(String[] args) {

        CyclicBarriercyclicbarrier = newCyclicBarrier(300);

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

            newTestThread(i,cyclicbarrier).start();

        }

       

       

    }

     

   

}

 

 

2.实现Runnable

package com.mq.test.testrunnable;

 

import java.util.concurrent.CountDownLatch;

import java.util.concurrent.atomic.AtomicInteger;

 

public classTestRunnable implements Runnable {

 

    private AtomicIntegeratomicInteger;

    private CountDownLatchcountdownlatch;

   

    public TestRunnable(AtomicInteger atomicInteger,CountDownLatch countdownlatch)

    {

        this.atomicInteger=atomicInteger;

        this.countdownlatch =countdownlatch;

       

    }

    @Override

    public void run() {

       

        atomicInteger.incrementAndGet();

        try {

          // countdownlatch是初始化一个初始值每次调用countDown 初始化值减一 直到为0调用countdownlatch.await被唤醒

            countdownlatch.countDown();

        }catch(Exception e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

        System.out.println(Thread.currentThread().getName()+"执行完了");

       

    }

  publicstaticvoidmain(String[] args)throws InterruptedException {

       AtomicInteger atomicInteger= new AtomicInteger(0);

       CountDownLatch countdownlatch = new CountDownLatch(300);

           for(inti=0;i<300;i++){

           new Thread(new    TestRunnable(atomicInteger,countdownlatch)).start();

       }

       countdownlatch.await();

       System.out.println("共有"+atomicInteger.get()+"个线程运行完毕");

   }

  

   

}

3.实现Callable

package com.mq.test.testcallable;

 

import java.util.ArrayList;

import java.util.List;

import java.util.Random;

import java.util.concurrent.Callable;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;

//当一个请求计算量很大或者操作磁盘文件,数据库读取很多时可以考虑使用Callable

//次接口可以获取异步线程的执行结果

//本方法主要是一个demo,每个线程随机一个值 最后获取所有线程的随机值相加

public classTestCallable implements Callable<Integer>  {

 

    @Override

    public Integer call()throws Exception {

        Randomran = newRandom();

        // TODO Auto-generated method stub

        return ran.nextInt(400);

    }

 

    public static void main(String[] args)throws InterruptedException,ExecutionException {

        ExecutorServicees = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

        List<TestCallable>list = newArrayList<TestCallable>();

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

            list.add(new TestCallable());

        }

        List<Future<Integer>>resultlist =es.invokeAll(list);

        int totalresult=0;

        for(inti=0;i<resultlist.size();i++){

            totalresult+=resultlist.get(i).get();

        }

        System.out.println("本次执行结果是"+totalresult);

    }

   

}

 

4.jdk 1.7 fork join框架

package com.mq.test.testforkjoin;

 

import java.util.concurrent.ForkJoinPool;

import java.util.concurrent.Future;

import java.util.concurrent.RecursiveTask;

// 此方法主要是单机版的mapreduce 可以利用多核cpu带来的计算能力并行计算

public classTestForkJoin extends RecursiveTask<Integer> {

     private staticfinallongserialVersionUID = -3611254198265061729L;

       

        public static final int threshold= 50;

        private int start;

        private int end;

       

        public TestForkJoin(int start,int end)

        {

            this.start = start;

            this.end = end;

        }

 

        @Override

        protected Integer compute()

        {

            int sum = 0;

           

            //如果任务足够小就计算任务

            boolean canCompute = (end -start) <= threshold;

            if(canCompute)

            {

                for (int i=start; i<=end;i++)

                {

                    sum += i;

                }

            }

            else

            {

                // 如果任务大于阈值,就分裂成两个子任务计算

                int middle = (start +end)/2;

                TestForkJoin leftTask = new TestForkJoin(start, middle);

                TestForkJoin rightTask = new TestForkJoin(middle+1,end);

               

                // 执行子任务

                leftTask.fork();

                rightTask.fork();

               

                //等待任务执行结束合并其结果

                int leftResult = leftTask.join();

                int rightResult = rightTask.join();

               

                //合并子任务

                sum = leftResult + rightResult;

       

            }

           

            return sum;

        }

       

        public static void main(String[] args)

        {

            ForkJoinPool forkjoinPool = new ForkJoinPool();

           

         

            TestForkJoin task = new TestForkJoin(1, 5000);

           

            //执行一个任务

            Future<Integer> result =forkjoinPool.submit(task);

           

            try

            {

                System.out.println(result.get());

            }

            catch(Exception e)

            {

                System.out.println(e);

            }

        }

}

原创粉丝点击