Java并发基础(上)——Thread

        并发编程可使咱们将程序划分为多个分离的,独立运行的任务。经过多线程机制,这些独立任务都将由执行线程来驱动。在使用线程时,CPU将轮流给每一个任务分配占用时间,每一个任务都以为本身在占用CPU,但实际上CPU时间是划分为片断分配给了全部任务。java

定义任务编程

继承Thread类多线程

      咱们能够继承Thread类,并重写run方法。并发

public class SimpleThread extends Thread {
    @Override
    public void run(){
        for(int i = 0; i < 5; i++){
            System.out.println(getName() + i);
        }
    }
    
    public static void main(String[] args) {
        SimpleThread thread = new SimpleThread();
        thread.start();
        System.out.println(Thread.currentThread().getName());
    }
}

实现Runnable接口异步

      固然,咱们还能够实现Runnable接口,并实现run接口,而后提交给Thread实例。ide

public class Task implements Runnable{
    public void run(){
        for(int i = 0; i < 5; i++){
            System.out.println(Thread.currentThread().getName() + i);
        }
    }
    public static void main(String[] args) {
        Thread thread = new Thread(new Task());
        thread.start();
        System.out.println(Thread.currentThread().getName());
    }
}

Callable与Futurespa

       咱们知道run方法是没有返回值的,也就意味着任务完成后没法获取结果,因此咱们须要Callable接口来帮助咱们返回任务结果,它和Runnable接口很类似,因此咱们也须要实现Callable接口的call方法。而Future接口则用来获取异步计算结果的,咱们对执行结果获取,取消,或者判断是否完成。可是Callable接口并无继承Runnable,因此并不能直接提交给Thread实例,因此咱们还须要FutureTask类,它同时实现了Runnable接口和Callable接口,咱们能够用FutureTask包装Callable对象,再提交给Thread实例。操作系统

import java.util.concurrent.*;

public class TaskWithResult implements Callable<Integer> {
    public Integer call(){
        int total = 0;
        for(int i = 0; i < 100; i++){
            total += i;
        }
        return total;
    }

    public static void main(String[] args) throws InterruptedException, ExecutionException{
        RunnableFuture<Integer> task = new FutureTask<Integer>(new TaskWithResult());
        Thread thread = new Thread(task);
        thread.start();
        while (!task.isDone()){
            System.out.println(task.get().toString());
        }
    }
}

 后台线程线程

       后台线程,也叫守护线程,是指程序在运行的时候在后台提供一种通用服务的线程,而且这种线程并不属于程序中不可或缺的部分。因此,当全部非后台线程结束时,后台线程也会被结束,无论后台线程是否完成。并且,后台线程的子线程也是后台线程。code

public class Daemon implements Runnable {
    @Override
    public void run() {
        for(int i = 0; i < 10; i++){
            try{
                Thread.sleep(1000);
                System.out.println(i);
            }catch (InterruptedException e){
                System.out.println(e.getMessage());
            }
        }
    }

    public static void main(String[] args) throws InterruptedException{
        Thread thread = new Thread(new Daemon());
        thread.setDaemon(true);
        thread.start();
        Thread.sleep(1000 * 5);
        System.out.println(Thread.currentThread().getName());
    }
}

        这里要注意setDaemon方法必需要在start以前调用,才能将其设置为后台线程。

线程的生命周期

新建(new)

       当线程被建立时,它只会短暂地处于这种状态。此时它已经分配了必须的系统资源,并执行了初始化。此刻线程已经有资格得到CPU时间了,以后调度器将把这个线程转变为可运行状态或阻塞状态。

就绪(Runnable)

       在这种状态下,只要调度器把时间片分配给线程,线程就能够运行。也就是说,在任意时刻,线程能够运行也能够不运行。只要调度器能分配时间片给线程,它就能够运行,这不一样于死亡和阻塞状态。

阻塞(Blocked)

       线程可以运行,但有某个条件阻止它的运行。当线程处于阻塞状态时,调度器将忽略线程,不会分配给线程任何CPU时间。直到线程从新进入了就绪状态,它才有可能执行操做。

       一个任务进入阻塞状态,可能有如下缘由:

       (1)经过调用sleep()使任务进入休眠状态,在这种状况下,任务在指定时间内不会运行。

       (2)经过调用wait()使线程挂起。直到线程获得了notify()或notifyAll()消息,线程才会进入就绪状态。

       (3)任务在等待某个输入/输出完成。

       (4)任务试图在某个对象上调用其同步控制方法,可是对象锁不可用,由于另一个任务已经获取了这个锁。

死亡(Dead)

       处于死亡或终止状态的线程将再也不是可调度的,而且不再会获得CPU时间,它的任务已结束,或再也不是可运行的。任务死亡的一般方式是从run()方法返回,可是任务的线程还能够被中断。

线程控制

线程优先级

       线程的优先级将该线程的重要性传递给调度器。尽管CPU处理现有线程集的顺序是不肯定的,可是调度器将倾向于让优先级最高的线程先执行。固然,这并不意味着优先权较低的线程将得不到执行(优先级不会致使死锁)。咱们能够用getPriority()来读取现有线程的优先级,经过setPriority()来修改它。尽管JDK有10个优先级,可是它与多数操做系统都不能映射的很好。因此设置优先级时,通常使用MAX_PRIORITY、NORM_PRIORITY、MIN_PRIORITY三种级别。

休眠(Sleep)

       在线程执行的过程当中调用sleep方法让其休眠(也就是进入阻塞状态)。sleep会抛出InterruptedException。

public class Sleep {
    public static void main(String[] args) {
        System.out.println("休眠开始");
        try{
            Thread.sleep(1000 * 2);
        }catch (InterruptedException e){
            System.out.println(e.getMessage());
        }
        System.out.println("休眠结束");
    }
}

让步(Yield)

      若是知道已经完成了run方法的循环的一次迭代过程当中所需的工做,就能够给线程调度机制一个暗示:你的工做已经作的差很少了,可让别的线程使用CPU了,这个

暗示将经过调用yeild做出,固然,这只是一种建议,没有任何机制保证它将会采纳。当线程切换出去后,只有优先级与当前线程相同,或优先级比当前线程更高的处于就绪的线程才会得到执行机会,所以彻底有可能线程转入就绪后,调度器又将其调度出来从新执行。

Join
   join能够一个让线程等待另外一个线程执行完成,调用线程将被阻塞,直到被join的线程执行完成

public class Task implements Runnable{
    public void run(){
        for(int i = 0; i < 5; i++){
            System.out.println(Thread.currentThread().getName() + i);
        }
        try{
            Thread.sleep(1000);
        }catch (InterruptedException e){
            System.out.println(e.getMessage());
        }
    }
    public static void main(String[] args) throws Exception{
        Thread thread = new Thread(new Task());
        thread.start();
        thread.join();
        System.out.println(Thread.currentThread().getName());
    }
}
相关文章
相关标签/搜索