java多线程
线程生命周期
- 新建状态:
顾名思义,就是新建一个线程。处于新建状态的线程有自己的内存空间,通过调用start方法进入就绪状态。 - 就绪状态:
这时已经具备了运行条件,但还没有分配到CPU。等待状态并不是执行状态,当系统选定一个等待执行的Thread对象后,它就会从等待执行状态进入执行状态,系统挑选的动作称之为“cpu调度”。一旦获得CPU,线程就进入运行状态并自动调用自己的run方法。 - 运行状态:
运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。
此时线程失去了cpu资源,就会又从运行状态变为就绪状态。当发生如下情况是,线程会从运行状态变为阻塞状态:
①、线程调用sleep方法主动放弃所占用的系统资源
②、线程调用一个阻塞式IO方法,在该方法返回之前,该线程被阻塞
③、线程试图获得一个同步监视器,但更改同步监视器正被其他线程所持有
④、线程在等待某个通知(notify)
⑤、程序调用了线程的suspend方法将线程挂起。不过该方法容易导致死锁,所以程序应该尽量避免使用该方法。
当线程的run()方法执行完,或者被强制性地终止,例如出现异常,或者调用了stop()、desyory()方法等等,就会从运行状态转变为死亡状态。 - 阻塞状态:
在阻塞状态的线程不能进入就绪队列。只有当引起阻塞的原因消除时,如睡眠时间已到,或等待的I/O设备空闲下来,线程便转入就绪状态,重新到就绪队列中排队等待,被系统选中后从原来停止的位置开始继续运行。 - 死亡状态:
当线程的run()方法执行完,或者被强制性地终止,就认为它死去。这个线程对象也许是活的,但是,它已经不是一个单独执行的线程。线程一旦死亡,就不能复生。 如果在一个死去的线程上调用start()方法,会抛出java.lang.IllegalThreadStateException异常。
多线程的实现方式
java中实现多线程的方式有四种:
1. 继承Thread类,重写run方法
2. 实现Runnable接口,重写run方法。
3. 通过Callable和FutureTask创建线程。
4. 通过线程池创建线程
前两种可以归为一类,都是通过重写run方法,run方法的返回类型为void,无返回值。由于java单继承,类继承了Thread,会导致无法继承其他类,同时继承Thread类实际上是无法达到资源共享的目的的,所以在实际开发中更多的是实现Runnable接口。后面两种有返回值可以归结为一类。
方法1:继承Thread类
package com.zhang.Thread.thread;
/**
* @Description : 继承Thread类
* @Author : zhangMing
* @Date : Created in 上午11:06 2018/3/20
*/
public class ThreadTest extends Thread {
volatile int i ;
@Override
public void run() {
for (; i < 10 ; i ++) {
System.out.println(Thread.currentThread().getName() + "执行了第"+i+"次");
}
}
public static void main(String[] arg){
ThreadTest threadTest = new ThreadTest();
ThreadTest threadTest1 = new ThreadTest();
ThreadTest threadTest2 = new ThreadTest();
ThreadTest threadTest3 = new ThreadTest();
threadTest.start();
threadTest1.start();
threadTest2.start();
threadTest3.start();
}
}
方式2:实现Runnable接口
package com.zhang.Thread.runnable;
/**
* @Description : 实现runnable接口
* @Author : zhangMing
* @Date : Created in 上午10:56 2018/3/20
*/
public class RunnableTest implements Runnable{
int i;
public void run() {
for (; i < 10 ; i ++){
System.out.println(Thread.currentThread().getName()+"执行了第"+i+"次");
}
}
public static void main(String[] arg){
RunnableTest runnableTest = new RunnableTest();
Thread thread = new Thread(runnableTest,"线程");
Thread thread1 = new Thread(runnableTest,"线程1");
thread.start();
thread1.start();
}
}
方法3:实现Callable接口
package com.zhang.Thread.callable;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
/**
* @Description : 实现callable接口
* @Author : zhangMing
* @Date : Created in 上午11:09 2018/3/20
*/
public class CallableTest implements Callable {
int i ;
public Object call() throws Exception {
for (; i < 10 ; i ++){
System.out.println(Thread.currentThread().getName()+"执行了第"+i+"次");
}
return Thread.currentThread().getName()+"执行完毕";
}
public static void main(String[] arg){
CallableTest callableTest = new CallableTest();
FutureTask futureTask = new FutureTask(callableTest);
FutureTask futureTask1 = new FutureTask(callableTest);
new Thread(futureTask,"aa").start();
new Thread(futureTask1,"bb").start();
try {
System.out.println(futureTask.get());
System.out.println(futureTask1.get());
}catch (Exception e){
}
}
}
方法4:线程池
package com.zhang.Thread.ThreadPool;
import com.zhang.Thread.callable.CallableTest;
import com.zhang.Thread.runnable.RunnableTest;
import com.zhang.Thread.thread.ThreadTest;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
/**
* @Description : 线程池
* @Author : zhangMing
* @Date : Created in 上午10:55 2018/3/20
*/
public class ThreadPool {
static ExecutorService executorService;
public static void main(String[] arg){
//官方推荐,会自动创建 销毁
executorService = Executors.newCachedThreadPool();
executorService.execute(new ThreadTest());
executorService.execute(new RunnableTest());
FutureTask futureTask = new FutureTask(new CallableTest());
executorService.execute(futureTask);
try {
System.out.println(futureTask.get());
}catch (Exception e){
}
//关闭
executorService.shutdown();
}
}
执行后会发现结果有时候会和自己想的有些差别,这就是线程不安全的问题。下一篇会详解一下线程安全。