1. 线程创建
进程:程序静止的,真正运行时的程序,才被称为进程。
线程:轻量级进程(Light Weight Process),程序中的一个顺序控制流程,同时也是CPU的基本调度单位,进程由1个或多个线程组成,彼此间完成不同的工作,交替执行,称为多线程。
JVM,**Java虚拟机是一个进程(单进程)**,当中默认包含主线程(main),可通过代码创建多个独立线程,与main并发执行。
线程组成
① CPU时间片:操作系统会为每个线程分配执行时间;
② 运行数据:
- 堆空间:存储线程需使用的对象,多个线程可以共享堆中的对象;
- 栈空间:存储线程需使用的局部变量,每个线程都拥有独立的栈;
③ 线程的逻辑代码。
① 继承父类 - Thread
① 继承Thread类
② 覆盖run()方法
③ 创建子类对象
④ 调用start()方法 - 启动线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
public class TestExtendsThread { public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.start(); for (int i = 1; i <= 50; i++) { System.out.println("Main:" + i); } } }
class MyThread extends Thread {
@Override public void run() { for (int i = 1; i <= 50; i++) { System.out.println("MyThread:" + i); } } }
|
② 实现接口 - Runnable
① 实现Runnable接口
② 覆盖run()方法
③ 创建实现类对象
④ 创建线程对象(Thread父类有参构造)
⑤ 调用start()方法 - 启动线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| public class TestImplementsRunnable { public static void main(String[] args) {
MyRunnable mr = new MyRunnable();
Thread t1 = new Thread(mr); Thread t2 = new Thread(mr);
t1.start(); t2.start(); for (int i = 1; i <= 50; i++) { System.out.println("Main:" + i); } } }
class MyRunnable implements Runnable {
public void run() { for (int i = 1; i <= 50; i++) { System.out.println(Thread.currentThread().getId() + " " + Thread.currentThread().getName() + " " + i); } } }
|
2. start()和run()的区别
- 启动该线程执行,java虚拟机自动调用这个线程的run方法。结果是,两个线程同时运行:当前线程(调用start()方法)和启动的线程(JVM执行了run方法)。
- start()方法来启动线程,真正实现了多线程并行运行。这时无需等待 run 方法体代码执行完毕,可以直接继续执行下面的代码或其他线程代码。
- 通过调用 Thread 类的 start()方法来启动一个线程, 这时此线程是处于就绪状态, 并没有运行。
- 方法 run()称为线程体,它包含了要执行的这个线程的内容,线程就进入了运行状态,开始运行 run 函数当中的代码。Run方法运行结束,此线程终止,然后 CPU 再调度其它线程。
3. 线程状态(5种)
如图所示:
初始New → 运行RUNNABLE → 等待WAITING(限期/无限期) → 阻塞BLOCKED → 终止TERMINATED
- JDK5之后,READY+RUNNING 合并为 **RUNNABLE(运行态)**。
4. 线程的常用方法
4.1 Thread构造方法
分配新的 Thread 线程对象:
1 2 3 4
| Thread() Thread(String name) Thread(Runnable target) Thread(Runnable target, String name)
|
4.2 Thread静态方法
1 2 3 4 5 6 7 8 9 10 11 12
| static Thread currentThread() 返回当前正在执行的线程对象的引用。常用Thread.currentThread().getName()输出线程名称。 static void dumpStack() 将当前线程的堆栈跟踪打印到标准错误流中。 static boolean holdsLock(Object obj) 返回 true如果当前线程拥有指定对象上的锁的监控。 static boolean interrupted() 测试当前线程是否已被中断。 static void sleep(long millis) 当前正在执行的线程休眠(暂停执行)为指定的毫秒数,根据精度和系统定时器和调度的准确性。 static void yield() 给调度程序的一个提示,当前线程愿意得到它当前的处理器的使用。
|
4.3 Thread成员方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| void start() 导致该线程开始执行;java虚拟机调用这个线程的 run方法。最常用!启动线程! long getId() 返回此线程的标识符。 String getName() 返回此线程的名称。 int getPriority() 返回此线程的优先级。 Thread.State getState() 返回此线程的状态。 boolean isAlive() 测试这个线程是否还活着。 boolean isDaemon() 如果该线程是守护线程。 boolean isInterrupted() 测试此线程是否已被中断。 void join() 等待该线程死亡。 void setDaemon(boolean on) 标志着该线程是 daemon线程或用户线程。 void setName(String name) 改变该线程的名称等于参数 name。 void setPriority(int newPriority) 更改此线程的优先级。 String toString() 返回此线程的字符串表示形式,包括线程的名称、优先级和线程组。
|
5. Callable接口
1 2 3
| public interface Callable<V> { public V call() throws Exception; }
|
特点:
- JDK5加入,与Runnable接口类似,实现之后代表一个线程任务;
- Callable具有泛型返回值,
可以声明异常
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class TestCallable { public static void main(String[] args) { ExecutorService es = Executors.newFixedThreadPool(3); ThisTask task = new ThisTask(); es.submit(task); } } class ThisTask implements Callable<Object> { @Override public Object call() throws Exception { for (int i = 1; i <= 50; i++) { Thread.sleep((int)(Math.random() * 1000)); System.out.println(Thread.currentThread().getName() + ":" + i); } return null; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class TestNonNameThread { public static void main(String[] args) { Callable<Object> c = new Callable<Object>() { @Override public Object call() throws Exception { int sum = 0; for (int i = 0; i <= 100; i++) { Thread.sleep(1000); sum += i; } return sum; } }; ExecutorService es = Executors.newFixedThreadPool(3); es.submit(c); System.out.println(es.toString()); Runnable r = new Runnable() { @Override public void run() { for (int i = 0; i <= 100; i++) { System.out.println(i); } } }; Thread thread2 = new Thread(r, "线程2"); System.out.println(thread2.toString()); } }
|
6. Future接口
1
| public interface Future<V>
|
特点:
- 异步接收 ExecutorService.submit() 所返回的状态结果,当中包含了call()的返回值;
- 方法:
V get()
以阻塞形式等待Future中的异步/并发计算
处理结果(call()的返回值)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class TestFuture { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService es = Executors.newFixedThreadPool(3); MyCall call = new MyCall(); MyCall2 call2 = new MyCall2(); Future<Integer> f = es.submit(call); Future<Integer> f2 = es.submit(call2); System.out.println( f.get() + f2.get()); } }
class MyCall implements Callable<Integer> { @Override public Integer call() throws Exception { Integer sum = 0; for (int i = 1; i <= 50; i++) { sum += i; } System.out.println(Thread.currentThread().getName() + ":" + sum); return sum; } }
class MyCall2 implements Callable<Integer> { @Override public Integer call() throws Exception { Integer sum = 0; for (int i = 51; i <= 100; i++) { sum += i; } System.out.println(Thread.currentThread().getName() + ":" + sum); return sum; } }
|