多线程细节:
1. 面试题: sleep 方法 和 wait 方法异同点是什么?
相同点: 可以让线程 处于 冻结状态.
不同点:
1.
sleep 必须指定时间
wait 可以指定时间, 也可以不指定时间.
2.
sleep 时间到 线程会处于 临时阻塞 或者运行.
wait 如果没有指定时间 , 必须要通过 notify 或者 notifyAll 唤醒.
3.
sleep 不一定非要定义在 同步中.
wait 必须要定义在同步中. (锁)
4.
都定义在同步中,
线程执行到 sleep, 不会释放锁. (因为 sleep 肯定能醒)
线程执行到 wait, 会释放锁. (wait 就 不一定 能醒)
5.
方法名不相同
// *** 此时的同步代码块中 有多个线程, 不会 出现 线程安全 问题.
// *** 因为里面 的线程 光有执行权是不够的, 还得 需要锁.
synchronized(obj)
{
// sleep(5000); // *** 5000 毫秒, 也就是 5 秒. // *** 释放执行权,
wait(); // *** 0 1 2 // *** 线程池. 这三个 线程 一旦 被唤醒, 都会处于 临时阻塞 状态.
code...
}
synchronized(obj){
notifyAll(); // *** 3 // *** 持有锁.
code...
// *** 释放锁 对于同步代码块 而言 是 隐式的, 会在 同步代码块的最后 释放锁.
}
2. 线程 如何 停止呢?
stop 方法 过时了, 看其 描述发现, 有其它 解决方案.
线程结束: 就是让 线程任务代码 执行完, run 方法结束.
run 方法 咋结束呢?
run 方法中 通常都定义 循环, (如果没有定义循环 就不要 开启 多线程了, 没有意义.), 只要 控制循环 就 哦了.
*** 注意: 万一线程 在 任务中 处于了 冻结状态, 那么 它 还能去判断标记吗? 不能!
咋办? 答: *** 通过 查阅 stop 方法的描述, 发现提供了一个 解决方法, 如果目标线程 等待很长时间, 则 应使用 interrupt 方法来 中断等待.
所谓的 中断 并不是 停止线程.
*** interrupt 功能是 将线程 的 冻结状态 清除, 让线程 恢复到 运行状态(让 线程 重新 具备 CPU 的执行资格).
*** interrupt 让线程 从 冻结状态 恢复 回来. 清除 其 中断 状态.
*** 因为是 强制性的, 所以会有 异常发生, 可以在 catch 中 捕获异常, *** 在 异常处理中, 改变标记 让 循环结束, 让 run 方法结束.
3. 守护线程: 后台线程, 一般创建的 都是前台线程。
前台 后台 线程运行时 都是一样的, 获取 CPU 的执行权执行。
只有结束的时候有些不同。
前台线程要通过 run 方法结束, 线程结束。
后台线程 也可以通过 run 方法结束, 线程结束, 还有另一种情况,
当进程中 所有的前台线程都 结束了, 这时 无论后台线程 处于什么样的状态, 都会结束 , 从而 进程结束。
进程结束 依赖的 都是 前台线程。
之所以这里称之为 守护线程, 无非是 后台线程 在 守护着 前台线程。
前台 线程们结束了, 后台 线程 就自动跟着 结束了。
4. 线程 的 优先级: 是 用 数字标识的: 1-10
其中默认 初始优先级 是 5。 最明显的 三个 优先级 1, 5, 10
setPriority(10); // *** 设置线程 的优先级。
setPriority(Thread.MAX_PRIORITY);
setPriority(Thread.MIN_PRIORITY);
setPriority(Thread.NORM_PRIORITY);
5. 线程组: ThreadGroup: 可以通过 Thread 的 构造函数 明确 新 线程对象 所属的 线程组。
线程组的好处: 可以对 多个 同组的线程, 进行 统一的操作。
默认都属于 main 线程组。
6. 线程 是可以 自己 取名字的。
例如:
Thread t1 = new Thread(d,"旺财"); // *** 旺财 线程名
Thread t2 = new Thread(d,"小强"); // *** 小强 线程名
可以自己 给 线程 取名 以 增强 程序的 阅读性。
例如:
输入线程, 运行线程 etc.
7. join 方法
主线程执行到这里, 知道 t1 要加入 执行, 主线程 释放了 执行权、 执行资格 并处于 冻结状态, 什么时候恢复呢?
等 t1 线程 执行完。
try{t1.join();}catch(InterruptedException e){}
try{t1.join();}catch(InterruptedException e){} // *** 一般这个方法 用于 临时 加入一个 运算的线程, 让 该 线程 运算完, 程序才会继续执行。
8. yield(); (static 静态的)
// *** 暂停 当前正在 执行的线程对象, 并执行 其它 线程。
Thread.yield(); // *** 线程 临时暂停。 将执行权 释放, 让其他 线程 有机会 获取 执行权。
// *** 嵌套类 也就是 内部类。
9. 开发中, 线程 匿名内部类 体现。
// *** 面试题
new Thread(new Runnable() // *** 就是 往里面 传递了 一个 线程任务 对象。 在 执行的时候, 就按照 这个对象的 任务来执行。
{
public void run(){
}
}).start();
// *** 面试题
new Thread(new Runnable() // *** 就是 往里面 传递了 一个 线程任务对象。 在 执行的时候, 就按照 这个对象的 任务来执行。
{
public void run(){
System.out.println("runnable run");
}
}){
public void run(){
System.out.println("subthread run");
}
}.start();
}
1 public class ThreadTest{ 2 3 public static void main(String[] args) { 4 5 /* 6 // *** 使用 匿名内部类的方式 创建一个 线程。 7 new Thread(){ // *** 这是一个 Thread 的子类对象, 可以 进行 覆盖 run 方法的操作。 8 9 public void run(){ 10 11 for(int x = 0; x < 40; x++){ 12 System.out.println(Thread.currentThread().getName() +"....X...." + x); 13 } 14 } 15 16 }.start(); 17 18 19 Runnable r = new Runnable(){ 20 21 public void run(){ 22 23 for(int x = 0; x < 40; x++){ 24 System.out.println(Thread.currentThread().getName() +"....Y...." + x); 25 } 26 27 } 28 29 }; 30 31 new Thread(r).start(); 32 33 34 35 for(int x = 0; x < 40; x++){ 36 System.out.println(Thread.currentThread().getName() +"....Z...." + x); 37 } 38 39 */ 40 41 // *** 面试题 42 43 new Thread(new Runnable() // *** 就是 往里面 传递了 一个 线程任务对象。 在 执行的时候, 就按照 这个对象的 任务来执行。 44 { 45 public void run(){ 46 47 System.out.println("runnable run"); 48 } 49 50 51 }){ 52 53 public void run(){ 54 55 56 System.out.println("subthread run"); // *** 执行 57 } 58 59 }.start(); // new Thread 后面是一个 大括号, 就是一个 子类. 60 61 } 62 //*** 子类 覆盖 父类, 运行的 时候 运行的 是 子类 方法. 63 64 } 65 66 67 68 /* 69 70 class Thread{ 71 72 private Runnable r; 73 Thread(Runnable r) 74 { 75 76 this.r = r; 77 78 } 79 80 public void run(){ 81 82 83 if(r != null){ 84 85 86 r.run(); // *** 这里调用的 是 Runnable 的 run 方法. 87 88 } 89 90 } 91 92 public void start(){ 93 94 run(); 95 96 97 } 98 99 } 100 101 class SubThread extends Thread{ // *** 子类 覆盖 父类, 运行的 时候 运行的 是 子类 方法. 102 103 public void run(){ 104 105 106 System.out.pritnln("subthread run"); 107 } 108 109 110 } 111 112 113 Runnable r = new Runnable(); 114 { 115 116 public void run(){ 117 118 119 System.out.println("runnable run"); 120 121 } 122 123 } 124 //Thread t = new Thread(r); 125 126 SubThread t = new SubThread(r); 127 128 t.start(); 129 130 131 // *** 这里先 调用 start 方法, 然后 调用 run 方法, 然后 判断 r 不为空, 然后 调用 Runnable 的 run 方法(因为 传进去的 参数 是 Runnable 的 对象 r), 然后 输出 runnable run. 132 133 134 */
原文:https://www.cnblogs.com/CYjiang/p/11805236.html