1. 进程与线程区别
线程是进程中独立运行的子任务。协程,coroutine,又称微线程。协程看上去也是子程序,但是内部可以中断,转而执行别到子程序。不需要切换线程上下文。
停止线程:Thread.stop()已被弃用,大多数停止一个线程使用到方法是Thread.interrupt()
方法,这个方法不会中止一个正在运行的线程,还需要加入一个判断才可以完成线程的中止。
this.interrupted()
:测试当前线程是否已经是中断状态,执行后会清除状态。
this.isInterrupted()
:测试当前线程是否已经是中断状态,不清除状态。
怎么停止线程? 可以在代码中判断当前线程是否被中断,如果被中断,停止操作。
还可以使用suspend()
挂起,来暂停线程,使用resume()
来恢复线程执行。
yield()
方法放弃CPU,但是时间不确定,可能刚放弃就又获得。
2. 并发访问
”非线程安全“问题存在于”实例变量“中,如果是方法内部到私有变量,则不存在”非线程安全“问题。
synchronized
锁可重入,也就是说当一个线程获取到一个对象锁后,再次请求此对象锁时是可以再次得到该对象的锁的。为什么可重入,对象持有锁后,还没释放时,如果想再次获取锁,如果不可重入,就会发生死锁。
死锁是必须要避免到,因为会造成线程假死。
3. volatile关键字
主要作用是使变量在多个线程间可见。(每次读取变量从主内存中读取),其致命缺点在于不支持原子性,因而会造成”线程不安全“。而synchronized
保证了原子性。同步状态下的变量从读到操作到存入主内存,必须在一个同步代码段执行完;而volatile
只能保证每次读是从主内存读,但是读的同时可能另一个线程在操作,还未写入。
主要作用在于变量到变化能被读取到。
4. 线程间通信
4.1 等待/通知机制
实现是在Object类中。
wait()
方法的作用是使当前执行代码的线程进行等待,直到接到通知或被中断为止。notify()
方法在调用前,必须获得该对象的锁,然后对一个处于wait状态的线程发出通知,**使他等待获取该对象锁。**在执行notify()
方法后,不会马上释放该对象锁,要等到该线程执行完后,退出同步代码块后,才会释放锁。如果对象锁释放,但是没有notify,其他wait状态的线程还会继续wait阻塞,直到有notify、通知。
这两个方法必须在同步代码块中执行。
4.2 通过管道进行线程间通信
pipeStream是一种特殊的流,用于在不同线程间直接传送数据。一个线程发送数据到输出管道,另一个线程从输入管道中读取数据。两个线程之间到通信。
join
方法阻塞当前线程,执行新线程。
4.3 ThreadLocal
不同线程拥有自己的值。
5. Lock
JUC中的ReentrantLock也能达到synchronized效果,功能更强大。
使用栗子:
public class MyService {
private Lock lock = new ReentrantLock();
public void testMethod() {
lock.lock();
for (int i = 0; i < 5; ++i) {
System.out.println("name " + Thread.currentThread().getName() + ": " + i);
}
lock.unlock();
}
}
使用Condition实现等待/通知。使用ReentrantLock也可以实现等待通知模式,但要借助Condition对象。
public class MyService {
private Lock lock = new ReentrantLock();
public Condition condition = lock.newCondition();
public void await() {
try {
lock.lock();
System.out.println("await time = " + System.currentTimeMillis());
condition.await();
}catch (InterruptedException ex) {
ex.printStackTrace();
}finally {
lock.unlock();
}
}
public void signal() {
try {
lock.lock();
System.out.println("signal time = " + System.currentTimeMillis());
condition.signal();
}finally {
lock.unlock();
}
}
}
6. 定时器Timer
Timer类到主要作用就是设置计划任务,当封装任务到类却是TimerTask类。
7. 单例模式
7.1 双检锁
public class MyObject {
private volatile static MyObject myObject;
private MyObject() {
}
public static MyObject getInstance() {
try {
// 准备工作
Thread.sleep(1000);
if (myObject == null) {
synchronized (MyObject.class) {
if (myObject == null){
myObject = new MyObject();
}
}
}
}catch (InterruptedException ex) {
ex.printStackTrace();
}
return myObject;
}
}
7.2 静态内部类
public class MyObject {
private static class MyObjectHandler {
private static MyObject myObject = new MyObject();
}
private MyObject() {
}
public static MyObject getInstance() {
return MyObjectHandler.myObject;
}
}
7.3 static代码块
public class MyObject {
private static MyObject myObject = null;
private MyObject() {
}
static {
myObject = new MyObject();
}
public static MyObject getInstance() {
return myObject;
}
}
7.4 枚举类
public enum MyObject {
INSTANCE;
public void tellEveryone(){
System.out.println(this.hashCode());
}
}
但是JUC才是java多线程到重点,后面再写。