Java并发编程(一)-什么是并发和创建线程的方式

什么是并发

        并发,在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。
       Java是一种多线程编程语言,我们可以使用Java来开发多线程程序。 多线程程序包含两个或多个可同时运行的部分,每个部分可以同时处理不同的任务,从而能更好地利用可用资源,特别是当您的计算机有多个CPU时。多线程使您能够写入多个活动,可以在同一程序中同时进行操作处理。根据定义,多任务是当多个进程共享,如CPU处理公共资源。 多线程将多任务的概念扩展到可以将单个应用程序中的特定操作细分为单个线程的应用程序。每个线程可以并行运行。 操作系统不仅在不同的应用程序之间划分处理时间,而且在应用程序中的每个线程之间划分处理时间。多线程能够在同一程序同中,进行多个活动的方式进行写入。

线程的生命周期

       线程在其生命周期中经历各个阶段。 例如,线程诞生,启动,运行,然后死亡。以下是线程生命周期的阶段

   新线程(New)

  新线程在新的状态下开始其生命周期。直到程序启动线程为止,它保持在这种状态。它也被称为出生线程。

   可运行(Runnable)

  新诞生的线程启动后,该线程可以运行。状态的线程被认为正在执行其任务。

   等待(Waiting)

  有时,线程会转换到等待状态,而线程等待另一个线程执行任务。 只有当另一个线程发信号通知等待线程才能继续执行时,线程才转回到可运行状态。

   定时等待(Timed Waiting)

  可运行的线程可以在指定的时间间隔内进入定时等待状态。 当该时间间隔到期或发生等待的事件时,此状态的线程将转换回可运行状态。

   终止(Dead)

  可执行线程在完成任务或以其他方式终止时进入终止状态。

线程优先级

       每个Java线程都有一个优先级,可以帮助操作系统确定安排线程的顺序。Java线程优先级在MIN_PRIORITY(常数为1)和MAX_PRIORITY(常数为10)之间的范围内。 默认情况下,每个线程都被赋予优先级NORM_PRIORITY(常数为5)。具有较高优先级的线程对于一个程序来说更重要,应该在低优先级线程之前分配处理器时间。 然而,线程优先级不能保证线程执行的顺序,并且依赖于平台。

创建线程的三种方式

   一是通过继承Thread,二是通过实现Runnable接口,三室使用Callable和Future创建线程。

Thread

  查看JDK里的Thread类,可以看到Thread实际上是实现Runnable接口:

    public class Thread implements Runnable

Runnable

  只有一个抽象方法:

    @FunctionalInterface
    public interface Runnable {
        public abstract void run();
    }

  Runnable相当于一个作业,而Thread才是真正的处理线程,我们需要的只是定义这个作业,然后将作业交给线程去处理。
  在实际项目开发中,实现Runnable接口比继承Thread类所具有的优势:

  1. 适合多个相同的程序代码的线程去处理同一个资源
  2. java不允许多继承,因此实现了Runnable接口的类可以再继承其他类。而继承了Thread就不能再继承其他类。
  3. 增加程序的健壮性,代码可以被多个线程共享,代码和数据独立

Callable

  和Runnable接口不一样,Callable接口提供了一个call()方法作为线程执行体,call()方法比run()方法功能要强大,call()方法可以有返回值。

通过扩展Thread类创建线程

  需要覆盖Thread类中的run()方法。 该方法为线程提供了一个入口点,可以把完整的业务逻辑放在此方法中。当创建了一个Runnable线程对象,可以通过调用start()方法启动它,该方法执行对run()方法的调用。 以下是一个简单的语法start()方法:

    class ThreadDemo extends Thread {
        private String threadName;
        ThreadDemo( String name) {
            threadName = name;
            System.out.println("创建线程:" +  threadName );
        }
        @Override
        public void run() {
            System.out.println("运行线程:" +  threadName );
            try {
                for(int i = 4; i > 0; i--) {
                    System.out.println(threadName + ":正在执行第" + i+"循环");
                    // Let the thread sleep for a while.
                    Thread.sleep(50);
                }
            }catch (InterruptedException e) {
                System.out.println("Thread " +  threadName + " interrupted.");
            }
            System.out.println("结束线程: " +  threadName);
        }
    }
    public class TestThread {
        public static void main(String args[]) {
            Thread T1 = new ThreadDemo( "Thread-1");
            T1.start();
            Thread T2 = new ThreadDemo( "Thread-2");
            T2.start();
        }
    }

通过实现Runnable接口创建线程

  需要实现由Runnable接口提供的run()方法。 该方法为线程提供了一个入口点,可将把完整的业务逻辑放在此方法中。当创建了一个Thread线程对象,可以通过调用start()方法启动它,该方法执行对run()方法的调用。 以下是一个简单的语法start()方法 :

    class RunnableDemo implements Runnable {
        private String threadName;
        RunnableDemo( String name) {
            threadName = name;
            System.out.println("创建线程:" +  threadName );
        }
        @Override
        public void run() {
            System.out.println("运行线程:" +  threadName );
            try {
                for(int i = 4; i > 0; i--) {
                    System.out.println(threadName + ":正在执行第" + i+"循环");
                    // Let the thread sleep for a while.
                    Thread.sleep(50);
                }
            }catch (InterruptedException e) {
                System.out.println("Thread " +  threadName + " interrupted.");
            }
            System.out.println("结束线程: " +  threadName);
        }
    }
    public class TestRunnable {
        public static void main(String args[]) {
            RunnableDemo R1 = new RunnableDemo( "Thread-1");
            //new Thread是实现Runnable接口的类的实例
            new Thread(R1).start();
            RunnableDemo R2 = new RunnableDemo( "Thread-2");
            new Thread(R2).start();
        }
    }

  实现Runnable接口的对象需要Thread类的构造函数实例化一个Thread对象后调用start()方法运行。这里需要注意的是:
  start()方法来启动线程,真正实现了多线程运行。这时无需等待run方法体代码执行完毕,可以直接继续执行下面的代码;通过调用Thread类的start()方法来启动一个线程, 这时此线程是处于就绪状态, 并没有运行。 然后通过此Thread类调用方法run()来完成其运行操作的, 这里方法run()称为线程体,它包含了要执行的这个线程的内容, Run方法运行结束, 此线程终止。然后CPU再调度其它线程。
  run()方法当作普通方法的方式调用。程序还是要顺序执行,要等待run方法体执行完毕后,才可继续执行下面的代码; 程序中只有主线程——这一个线程, 其程序执行路径还是只有一条, 这样就没有达到写线程的目的。
  在实际项目中通常是使用线程池来管理项目。

通过实现Callable Future FutureTask创建线程

Callable

  Callable中有一个call()函数,但是call()函数有返回值,而Runnable的run()函数不能将结果返回给客户程序。通过get方法获取返回值,同时会阻塞。

Future

  Executor就是Runnable和Callable的调度容器,Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果操作。

FutureTask

  FutureTask实现了Runnable,因此它既可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行。并且还可以直接通过get()函数获取执行结果,该函数会阻塞,直到结果返回。因此FutureTask既是Future、Runnable,又是包装了Callable( 如果是Runnable最终也会被转换为Callable ), 它是这两者的合体。具体使用参考如下:

public class TestCallable {
    public static void main(String[] args) throws Exception {
        //Future
        ExecutorService executor = Executors.newCachedThreadPool();
        Callable callable=new CallableDemo();
        Future<Long> future=executor.submit(callable);
        //FutureTask
        FutureTask<Long> futureTask=new FutureTask(callable);
        executor.submit(futureTask);
        //注意这种方式和第一种方式效果是类似,只不过一个使用的是ExecutorService,一个使用的是Thread
        new Thread(futureTask).start();
        
        System.out.println(future.get());
        System.out.println(futureTask.get());
        
        executor.shutdown();
    }
}
class CallableDemo implements Callable<Long> {
    @Override
    public Long call() throws Exception {
        return System.currentTimeMillis();
    }
}
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值