永远记住:线程安全永远只是为了保护共享的成员变量!
与方法、类、局部变量什么的都没关系!!!data01\src\data\filemerge\LogFiles.java
(方法使用就压栈啊,局部变量也在栈中啊,只有成员变量需要线程出栈在共享内存中改。)
实现线程
第二种方式更常用,因为还可以extends,更灵活!
方法一:MyThread t = new MyThread();
方法二:Thread t = new Thread(new MyRunable());
方法二:(采用匿名内部类)
方法三:实现接口interface Callable< V > call()方法,有返回值
获取返回值get()方法会导致当前线程阻塞:
方法二、三实现区别:
重要 线程的生命周期
一个字一个字理解! 背会这张图!
线程 声明自己currentThread()、睡觉sleep()、让位yield()。都是自己说了算的,所以是静态方法!
静态方法一:获取当前线程 Thread.currentThread();
静态方法二:阻塞当前线程 Thread.sleep(lang millis);
也可以使用TimeUnit:
面试题:
唤醒睡眠:线程.interrupt()
终止线程:
线程.stop();(已过时,不建议使用)会直接杀死线程
使用布尔判断
线程调度(了解)
优先级高,每次抢到的时间片多。
实际项目开发中服务器已经将线程的定义、创建、启动都已经实现完,所以以上内容不是很重要。
重点开始 线程安全问题
局部变量就没有线程安全问题,因为局部变量不共享!
synchronized
synchronized()确实是 在内存中 判断线程是否共享括号中的对象锁
锁粒度大并发度会比较低
synchronized(🔒【是需要同步线程的一个共享对象】){
...代码块尽量小...
}
出现在static方法的synchronized默认是类🔒:(类锁就这一种用法)
当🔒(共享对象)被占用时,共享此对象的其他任何线程就不能再执行任何synchronized方法体。
死锁
去看javase\test05\src\com\neuq\ticketing
守护线程
setDaemon(true)设置守护线程
定时器
schedule(定时任务,第一次执行时间,间隔多久执行一次)
定时器总结:定时器Timer就是一个线程类
- Timer timer = new Timer(); ===> timer.start();timer就是一个Timer线程
- timer.schedule()就相当于给timer线程赋任务,赋予后立即执行下一句 (至于这个任务什么时候真正执行 那就是timer线程内部的事)
- 要是重新timer.schedule(新任务);那么上个任务等肯定就无法执行了
wait();notify();
面试题
wait(long timeout): timeout:最大等待时间(毫秒),超过会被唤醒,再次进入锁池
使用wait();和notify();
注意:wait()永远都和while()循环结合使用!(防止虚假唤醒)
while()判断线程需要等待,线程进入while循环。线程遇见wait()后会释放对象锁同时进入等待池等待!此后,此线程被唤醒后又抢到锁,将从wait()语句后继续执行。循环再判断是否需要等待…
synchronized(this){
while(需要等待的条件){
this.wait();
}
执行语句...
}