JAVA线程

线程的创建和启动

JAVA使用Thread代表线程,所有线程对象都是Thread或其子类的实例

继承Thread类创建线程类

通过重写run方法来定义线程需要完成的任务,然后通过start来启动线程。

实现Runnable接口创建线程类

先定义runnable接口的实现类,重写该接口的run()方法,之后创建实现类的实例,以该实例作为Thread的target方法创建Thread对象,

Thread t = new Thread(target,name)

t.start()

也就是说Thread类创建线程类可直接作为线程对象,Runnable接口创建线程类只能作为线程对象的target,Runnable接口创建多线程时,Thread类的作用就是把run()方法包装成线程执行体。

采用Runnable接口创建线程类可以共享线程类的实例变量

使用Callable和Future创建线程

Java5开始提供了Callable接口,其提供了一个call()方法可以作为线程执行体,但call()比run()更为强大。

call()可以有返回值;

call()可以声明抛出异常;

因此,我们可以尝试使用Callable作为Thread的target,但是Callable并不是Runnable子类,不能被当做target使用;

JAVA5提供了Future接口来代表call()的返回值,并为Future接口提供了一个FutureTask实现类,该实现类实现了Future接口,并实现了Runnable接口–因此可以作为thread的target;

public class thread_ extends Thread{
    public static void main(String args[]) {

        thread_ t = new thread_();

        FutureTask task = new FutureTask(new callable_());
        new Thread(task,"Callable").start();

    }


    static class callable_ implements Callable {
        @Override
        public Object call() throws Exception {
            int i = 0;
            for(; i<100;i++){
                System.out.println(Thread.currentThread().getName()+" "+i);
            }
            return i;
        }
    }

}

创建线程方式对比

采用runnable和Callable:

线程只是实现了接口,还可以继承其他类,且多个线程可以共享一个target对象,适合多个相同线程处理同一份资源。

采用thread:

编程简单;

一般使用runnable和Callable来创建线程

线程的生命周期

线程共有5种状态:新建、就绪、运行、堵塞、死亡;

新建和就绪状态

线程被new出来后就处于新建状态,由JAVA虚拟机为其分配内存,并且初始化其成员变量的值,此时线程并为表现出任何的动态特征;

线程对象调用start()后就处于就绪状态,JAVA虚拟机会为其创建方法调用栈和程序计数器,此时线程准备好运行的所有条件,至于何时开始运行,取决于JVM线程调度器的调度。

运行和堵塞状态

线程开始执行run()方法的线程执行体,其就进入了运行状态;

当发生如下状况,线程会进入堵塞状态:

调用sleep()主动放弃占用的CPU资源;

试图获得一个正在被其他线程持有的同步监视器;

调用一个堵塞式IO方法;

等待某个通知;

程序调用了线程的suspend()方法将线程挂起,(该方法容易导致死锁,尽量避免使用)

死亡状态

线程以以下三种方法结束后,处于死亡状态:

run()或者call()执行完成,程序正常结束;

抛出一个未被捕获的异常或error;

直接调用stop()方法强制结束;(该方法容易导致死锁,尽量避免使用)

可以使用isAlive()方法测试线程状态,当为新建、死亡两种状态时返回false,其余返回true;

控制线程

join线程

让一个线程等待另一个线程完成;当在某个线程执行流中调用其他线程的join()时,调用线程会被堵塞,直到被join的线程执行完;

后台线程

后台线程所示在后台运行,为其他线程提供服务的线程,如果所有前台线程都死亡,后台线程也会自动死亡;

调用Thread对象的setDaemon(true)方法可将该线程设置成后台线程,

线程睡眠sleep()

让当前执行的线程暂停一段时间;

改变线程优先级

优先级高的线程可获得较多的执行机会,默认优先级为父线程的优先级,可使用setPriority(int new Priority),getPriority()设置和获得

线程同步

线程安全问题

两个进程并发修改同一个文件时,可能造成异常;JAVA引入了同步监视器来解决这个问题,使用同步监视器的通用方法为同步代码块:

synchronized (obj){
    //同步代码块代码
}

其中obj代表着一个同步监视器,上面代码的含义是,线程开始执行同步代码块之前,必须先获得对同步监视器的锁定。任何时可只能有一个线程可以获得对同步监视器的锁定,同步代码块执行完成后,线程会释放对同步监视器的锁定。

JAVA允许任何对象作为同步监视器,但同步监视器的目的是阻止并发访问同一个资源,因此通常使用可能被并发访问的共享资源充当同步监视器。

同步方法

同步方法就是使用synchronized关键字来修饰某个方法,对于同步方法而言,无需指定同步监视器,其同步监视器就是This,也就是调用该方法的对象。

释放同步监视器的锁定

线程会在下面情况释放锁定:

同步方法或代码块执行结束后释放;

同步方法或代码块遇到break,return等情况终止时释放;

出现未处理的error或exception释放;

程序执行了同步监视器线程的wait()方法时释放

注意使用sleep或suspend不会释放锁定

同步锁

JAVA5后可通过同步锁对象实现同步,由Lock对象充当;Lock也是控制多个线程对共享资源进行访问的工具,比起同步代码块更为方便灵活,

每次只能有一个线程对lock对象加锁,线程开始访问共享资源之前应先获得Lock对象。

死锁

当两个线程相互等待对方释放同步监视器时就会发生死锁;

线程通信

Object类提供了三个方法:

wait():导致当前线程等待,直到其他线程调用该同步监视器的notify方法或notifyAll()方法来唤醒该线程,或者是自定的时间达到后。

notify():唤醒此同步监视器上等待的单个线程

notifyAll():唤醒此同步监视器上等待的所有线程

Condition

如果使用Lock对象来保证同步而不是Synchronized,就无法使用上面的方法进行线程通信,JAVA提供了一个Condition类保持协调,使用Condition可以让那些已经得到Lock对象却无法继续执行的线程释放Lock对象,企业能唤醒其他处于等待的线程。

Condition提供了三个类似的方法:

await();signal();signalAll()

堵塞队列

BlockingQueue:当生产者线程试图向其中取元素时,如果队列为空,则线程堵塞;线程试图存元素时,如果队列满,则线程堵塞;

BlockingQueue提供下面两个方法:

put(E e):尝试把e元素放入BlockingQueue中,若满则堵塞;

take():取出一个元素,若空则堵塞;

除此之外BlockingQueue还能使用Queue的一些通用方法;

线程组和未处理的异常

JAVA使用ThreadGroup来表示线程组,可以对一批线程组进行分类管理,JAVA允许程序直接对线程组进行控制,对线程组的控制相当于同时控制这批线程;

每个线程都属于一个线程组,没有显示指定的话就属于默认线程组。默认情况下,子线程与其父线程属于同一组;

线程只能在new的时候指定其线程组,之后不能改变;

ThreadGroup(String name);创建新线程组,名字为name;

ThreadGroup(ThreadGroup parent,String name);以指定的名字,指定的父线程组创建一个新线程组;

线程池

线程池在系统启动时就创建大量空闲线程,程序讲一个Runnable或者Callable对象传递给线程池,线程池就会启动一个线程执行他们的run()或call()方法,结束完毕后返回线程池成为空闲状态。

使用如下:

Executors类的静态工厂创建方法创建一个Executor对象,返回一个线程池。

创建线程实现类;

使用submit()方法提交runnable()实例;

使用shutdown()关闭线程池

ForkJoinPool

可以看下面的文章,讲一个任务拆分成多个小任务进行计算,再讲小人物结果合并成总的计算结果。ForkJoinPool是ExecutorService的实现类;

https://www.jianshu.com/p/91e504c910c9

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值