Java并发之线程机制

并发

先说说Java代码的执行机制:java代码–》编译后成为java字节码–》字节码被类加载器加载到JVM–》JVM执行字节码–》最终转换成汇编指令在CPU执行

关于并发:

Java实现并发的方式也有多种。

1. 基本的线程机制

1.1 实现线程的基本方法:

(1) 实现Runnable接口来定义任务

通过实现Runnable接口并编写run()方法来是实现一个线程类,注意此线程没有返回值。

public class MyThread implements Runnable{
    public void run(){
    }
}
//使用:
MyThread myThread = new MyThread();
myThread.run();//开始执行线程

(2) 继承Thread类

将一个实现了Runnable接口的线程类作为参数传递给Thread构造器来实现线程:

Thread thread = new Thread(new MyThread());
thread.start();//开始执行线程,start()方法会自动调用run()方法。其实start()会很快的返回,因为这个start()方法是有由main这线程执行的

1.2 关键方法解析

(1) Thread.yield()方法:

这是一个静态方法,对该方法的调用表示对线程调度器的一种建议,声明:我已经执行完声明周期中最重要的部分了,此时可以把CPU切换给别的线程使用了。(简单点理解可以是降低当前线程的优先级,主动让出CPU)

1.3 使用Executor执行器(启动线程的优先选择)

Executor是在客户端和执行任务中间提供了一个间接层,帮我们管理线程对象从而简化并发编程。

我们一般使用Executor的子接口ExecutorService,ExecutorService知道如何构建恰当的上下文来执行Runnable对象。下面是一个典型的例子:

public class CachedThreadPool {
  public static void main(String[] args) {
    ExecutorService exec = Executors.newCachedThreadPool();
    for(int i = 0; i < 5; i++)
      exec.execute(new LiftOff());
    exec.shutdown();
  }
}

这是很常见的情况,单个Executor来创建和管理所有的任务。

shutdown()方法的调用可以禁止新的任务提交给这个Executor,当前线程(示例中的main线程)将继续运行shutdown()调用之前所提交给Executor的所有任务,直到全部完成之后这个程序将尽快退出。

Executors创建的一些常用的线程池:

线程池名称区别
newCachedThreadPool()在程序执行过程中通常会创建与所需数量相同的线程,然后在它回收旧线程时停止创建新的线程。
newFixedThreadPool(int)根据参数一次性预先执行代价昂贵的线程分配,但是也在初始时就限制了线程的数量。
newSingleThreadExecutor创建一个单线程执行程序,如果提交了多个任务,将会把这些任务排队,每个任务都需要等待上一个任务结束才能执行。

1.4 从任务中产生返回值

Runnable是执行工作的独立任务,但是它没有返回值。如果我们希望Task在完成后能够返回一个result,那么可以通过实现Callable接口实现。Callable是一种具有类型参数的泛型,它的类型是从call()(而不是run()方法)中返回的值的类型。并且使用ExecutorService.submit()方法调用它。下面是一个简单示例:

import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
 * 从任务中产生返回值;返回值类型为Callable泛型的类型
 * @author LL
 */
class TaskWithResult implements Callable<String> {
    private int id;
    public TaskWithResult(int id){
        this.id = id;
    }
    //任务
    public String call() throws Exception {
        return "result of TaskWithResult " + id;
    }
}

/**
 * function: 从任务中产生返回值.并打印
 * @author LL
 */
public class CallableDemo {
    public static void main(String[] args) {
        ExecutorService exec = Executors.newCachedThreadPool();
        //Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结.
        //这个list用来保存每个任务的返回结果
        ArrayList< Future<String> > results = new ArrayList<Future<String>>();

        for (int i=0; i<10; i++){
            //submit()提交一个返回值的任务用于执行,返回一个表示任务的未决结果的 Future。
            //把返回的结果添加到List
            Future<String> fs = exec.submit(new TaskWithResult(i));
            results.add(fs);
        }
        for (Future<String> fs : results) {
            try {
                //阻塞等待结果
                System.out.println(fs.get());
            } catch (Exception e) {
                e.printStackTrace();
            } finally{
                exec.shutdown();//启动一次顺序关闭,执行以前提交的任务,但不接受新任务。
            }
        }
    }
}

submit()方法会产生Future对象,它用Callable返回结果的特定类型进行了参数化。我们可以通过isDone()方法查看Future是否已经完成。当任务完成时我们可以通过调用get()方法来获取该结果。不过不用isDone()方法检查,get()方法将会阻塞直到获取到callable执行获取到结果。

1.5 休眠

影响任务行为的一种简单方法是调用sleep()方法,这将使任务中止执行给定的时间。现在一般用TimeUnit这个类显示指定的函数代替原来的函数:当前线程休眠

//Thread.sleep(100);
TimeUnit.MILLISECONDS.sleep(100);

1.6 优先级

我们一般在run()方法里面设置线程的优先级,如下所示

public void run(){
    Thread.currentThread().setPriority(int)
    ......

}

不同的系统有不同等级的优先级,windows下一般只有7个优先级,而Solaris有2^31 个优先级,所以我们一把只设置三个优先级:Thread类下的静态常量
- static int MAX_PRIORITY 线程可以具有的最高优先级。
- static int MIN_PRIORITY 线程可以具有的最低优先级。
- static int NORM_PRIORITY 分配给线程的默认优先级。

1.7 后台线程

后台线程:指程序运行时在后台提供一种通用服务的线程,并且这种线程并不属于程序中不可或缺的部分。故当程序中所有的非后台线程结束时,程序也就终止了同时会杀死进程中所有的后台线程。

1)设置线程为后台线程的方法:

Thread t = new Thread(new LiftOff());
t.setDaemon(true);//设置为后台线程

1.8 加入一个线程 join()方法

一个线程A可以在另外的一个线程B之上(一般是run()方法里面)调用join方法,其结果是等待一段时间直到后一个线程结束才继续执行。比如:

  1. 若在线程t上(t的run()方法中)调用线程s的s.join()方法(s一般作为t的构造器参数传入),则线程t将别挂起,直到线程s结束为止,t才可恢复继续执行。
  2. 若在线程t上(t的run()方法中)调用t.join(),则当前线程会被挂起,直到线程t结束。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值