第一章 java多线程技能

创建线程的两种方式

a.、继承Thread类

b、实现Runable接口

优缺点分析:Thread类实际上也是实现的runable接口,java中只能单继承,因此继承Thread类的话会有局限。

线程的启动顺序

使用多线程技术时,代码的运行结果与代码的执行顺序或者调用顺序无关。是cpu以一种不确定方式或者说是在不确定的时间调用线程中的run方法。

调用start方法时,只是告诉线程规划器该线程已处于就绪状态,可以调用该线程的run方法。因此执行start不代表该线程立即被执行,调用start方法的顺序不代表线程启动的顺序。

多次调用start方法时,会抛出IllegalThreadStateException。

this.getName()和Thread.currentThread().getName()

getName()方法为Thread类中的方法,实现Runable接口的线程对象不能调用此方法。

Thread.currentThread().getName()在两种实现线程的方式中都可以用。

两者是同一个线程对象时,返回结果是一样的。

当将一个Thread对象当做构造参数传递给另一个Thread对象时,this代表传递的这个对象的引用,Thread.currentThread()代表当前的执行线程对象的引用。

例如:

public classmyThreadextendsThread {

publicmyThread() {

System.out.println("构造函数:Thread.currentThread().getName()="+Thread.currentThread().getName());

System.out.println("构造函数:this.getName="+this.getName());

System.out.println("构造函数:this==Thread.currentThread()"+(this==Thread.currentThread()));

}

public voidrun() {

System.out.println(Thread.currentThread().getName());

System.out.println(this.getName());

System.out.println("this==Thread.currentThread()"+(this==Thread.currentThread()));

}

public static voidmain(String[] args) {

Thread thread1 =new myThread();

thread1.setName("b");

Thread thread =newThread(thread1);

thread.setName("a");

thread.start();

}

}

执行结果为:

构造函数:Thread.currentThread().getName()=main

构造函数:this.getName=Thread-0

构造函数:this==Thread.currentThread()false

a

b

this==Thread.currentThread()false

停止线程

a、Thread.stop() 此方法unsafe,已经被废止。因为强制一个线程停止有可能导致一些清理工作无法进行,另外一个情况就是对锁定的对象进行解锁,导致数据得不到同步的处理,出现数据不一致的情况。

b、建议使用Thread.interrupt(),它是给正在执行的线程打了个标记,并没有立刻停止。特殊情况:如果线程sleep后调用interrupt会报异常。如果先调用interrupt再进入睡眠,则会将睡眠之前的代码逻辑执行完,然后进入睡眠时抛出异常。

如果想立刻停止线程有两种方法:结合interrupted()判断是否已经停止,然后抛出异常;结合interrupted()判断是否已经停止,然后return。建议抛出异常,这样可以进行一些其他处理操作。更可控。使用return会造成污染。


c、使用退出标志

this.interrupted()和this.isInterrupted()

this.interrupted为静态方法,作用是判断当前线程是否是中断状态,执行后会将状态标志清除为false;

this.isInterrupted为实例方法,作用是判断Thread对象是否是中断状态。

suspend和resume线程暂停和恢复

这两个方法也已经被废弃。原因和stop相似,容易造成数据不一致,或者锁死公共资源。

yield方法

- 作用是让出cpu。但是让出多长时间不一定,有可能刚刚让出,又马上获得。

守护线程

java中线程分为用户线程和守护线程两种。守护线程通过setDaemon(true)来设置一个线程为守护线程,必需在调用start之前设置,否则抛出异常。作用是守护非守护线程,当进程中没有非守护线程了,守护线程会自动销毁。典型的守护线程有GC(垃圾回收器),servlet容器初始化后生成的服务线程。

获得线程的返回值

第一种方法:通过类变量和方法返回数

publicclassMyThreadextendsThread

{

privateString value;

publicvoidrun()

{

value ="通过成员变量返回数据";

}

publicstaticvoidmain(String[] args)throwsException

{

MyThread thread =newMyThread();

thread.start();

thread.join();

System.out.println("value:"+ thread.value);

}

}

通过join使线程执行从异步变成同步,等线程执行完后获取该线程的变量。

第二种方法:通过实现callable接口

importjava.util.concurrent.Callable;

publicclassMyThread2implementsCallable {

@Override

publicString call()throwsException {

String string="通过实现Callable借口返回";

returnstring;

}

}

publicstaticvoidmain(String[] args) {

ExecutorService executorService=Executors.newCachedThreadPool();

Callable callable=newMyThread2();

Future future=executorService.submit(callable);

try{

if(future.isDone()){

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

}

}catch(Exception e) {

e.printStackTrace();

}

}

必须使用ExecutorService的submit方法来执行,返回一个Future对象。可以使用isDone()方法检测future是否完成,完成后可以调用get()方法获得future的值,如果直接调用get()方法,get()方法将阻塞值线程结束。

线程池

类的继承关系:

ThreadPoolExcuter--->AbstractExcuterService-->ExcuterService-->Excuter

构造器参数:

a、 corePoolSize  核心池线程数。创建线程池后,默认里面是空的,知道有任务进来,开始创建线程。可以调用pre方法预先生成corePoolSize个线程。创建的线程数大于corePoolSize时,则会把任务放进缓存队列中。

b、 maximumPoolSize最大线程数 

c、 keepAliveTime  线程存活时长 。表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;

d、unit:参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性。

e、workQueue:一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响,一般来说,这里的阻塞队列有以下几种选择:

ArrayBlockingQueue;

LinkedBlockingQueue;

SynchronousQueue;

f、threadFactory:线程工厂,主要用来创建线程;

g、handler:表示当拒绝处理任务时的策略,有以下四种取值:

ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。

ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。

ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)

ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

你可能感兴趣的:(第一章 java多线程技能)