Thread类
进程与线程
进程
程序是静止的,运行中的程序是进程
特征:
- 动态性:动态的占用内存、CPU、网络…
- 独立性:各进程相互独立,有自己的内存空间
- 并发性:如果 CPU 单核,一个时刻只能一个进程被执行。CPU 会分时轮询切换依次服务进程,因为切换速度快,感受就是各个进程都在同时执行
并行:
线程
- 线程属于进程,一个进程至少一个线程
- 线程开销相对于进程少
- 线程也有并发性
乱七八糟:
StringBuilder 是不安全的,而 StringBuffer 是安全的,但是淘汰了,性能差
SringBuffer的 append 方法,为了实现同步,很多方法使用 synchronized 修饰
底层字符串都是由 char 数组
StringBuilder和StringBuffer的append(String str)方法都是通getChars方法来实现字符串拼接的
关于变量不可见
原因
- JMM( Java Memory Model ),所有共享变量存放于主内存,每个线程有工作内存,保留了变量的副本,所有线程所有的操作都在操作副本
解决方法
- volatile
- 子线程修改了变量后,当变量写入主内存,会失效其他线程的此变量的副本,其他线程操作此变量时,会从主内存 copy 最新的值,使得变量可见,区分 synchronized,两者不同
- synchronized
- 线程拿到锁,清空工作内存,从主内存 copy 共享变量到工作内存,变量如果有修改,会将修改的变量刷新回主内存,释放锁
线程状态
共 6 种
1 2 3 4 5 6 7 8
| public enum State { NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED; }
|
注意事项
sleep、wait、yield
- sleep 使当前线程让出了 CPU,但是,当前线程仍然持有它所获得的监视器锁
- wait 同时让出 CPU 资源和监视器锁
wait(0) 表示无限等待
sleep(0) 会让其他线程有机会优先执行,调用 sleep(0) 的线程的状态可能变成 TIMED_WAITING
yield 指当前线程愿意让出 CPU,但是对于 CPU 这只是一个建议,要不要让看厂商调度
- yield 顶多会让当前线程状态从 RUNNING 变成 READY,并不会退出 RUNNABLE
join
注意 join 方法有加 synchronized
,说明执行某个线程实例的 join 方法必须拿到对象锁( this 锁 ),即 myThread 对象所关联的监视器对象
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
| public final void join() throws InterruptedException { join(0); } public final synchronized void join(long millis) throws InterruptedException { long base = System.currentTimeMillis(); long now = 0;
if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); }
if (millis == 0) { while (isAlive()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }
|
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
| public static void main(String[] args) { System.out.println(Thread.currentThread().getName() + ": main 开始");
Thread myThread = new Thread(() -> { System.out.println(Thread.currentThread().getName() + ": 开始"); System.out.println(Thread.currentThread().getName() + ": 要睡觉了"); try { Thread.sleep(1000); System.out.println(Thread.currentThread().getName() + ": 醒了"); System.out.println(Thread.currentThread().getName() + ": 结束"); } catch (InterruptedException e) { e.printStackTrace(); } }, "myThread");
try { myThread.start(); System.out.println(Thread.currentThread().getName() + ": 我要等下面的线程执行完我才继续"); myThread.join(); System.out.println(Thread.currentThread().getName() + ": 上面的线程执行完了"); System.out.println(Thread.currentThread().getName() + ": 退出"); } catch (InterruptedException e) { e.printStackTrace(); }
}
|
main 方法中调用了 myThread.join()
,会无限等待,等到 myThread 执行结束( 线程结束默认会执行 this.notifyAll
),main 线程会被唤醒,继续执行,发现 myThread 的 isAlive
是 false,join 执行完毕
1 2 3 4 5 6 7 8
| main: main 开始 main: 我要等下面的线程执行完我才继续 myThread: 开始 myThread: 要睡觉了 myThread: 醒了 myThread: 结束 main: 上面的线程执行完了 main: 退出
|
而如果 main 方法中调用了 myThread.join(500)
,main 只会等待 0.5 s,发现 myThread 还是活着,那就 break
1 2 3 4 5 6 7 8
| main: main 开始 main: 我要等下面的线程执行完我才继续 myThread: 开始 myThread: 要睡觉了 main: 上面的线程执行完了 main: 退出 myThread: 醒了 myThread: 结束
|
参考文章