实现多线程的两种方式
线程五大状态
新建(new thread())
就绪(调用 start() 方法返回后)
运行(真正开始执行 run() 方法)
阻塞(sleep / io 阻塞/获取锁/等待某个触发条件等等)
死亡( run() 方法正常退出 / 未捕获异常终止了 run() 方法)
为了确定线程在当前是否存活着(要么是可运行的,要么是被阻塞了),需要使用 isAlive() 方法。如果是可运行或被阻塞,返回true; 如果线程仍旧是new状态且不是可运行的, 或者线程死亡了,返回false;
线程安全
线程的工作原理:jvm有一个main memory,而每个线程有自己的 working memory,一个线程对一个variable进行操作时,都要在自己的working memory里面建立一个copy,操作完之后再写入main memory。多个线程同时操作同一个variable,就可能会出现不可预知的结果。
实现方式:
1 给方法增加synchronized修饰符,方法可为静态或者非静态 但不能是抽象方法;
2 锁机制;
用 synchronized 的关键是建立一个 monitor(监听器),这个 monitor 可以是要修改的 variable(变量) 也可以其他你认为合适的 object(对象)比如method(方法),然后通过给这个monitor 加锁来实现线程安全,每个线程在获得这个锁之后,要执行完 load 到 working memory -> use&assign -> store到 main memory 的过程,才会释放它得到的锁。这样就实现了所谓的线程安全。
ReentrantLock 与 Synchronized 区别
1 如果使用 synchronized ,如果A不释放,B将一直等下去,不能被中断;如果使用 ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的 事情;
2 synchronized 是在 JVM 层面上实现的,不但可以通过一些监控工具监控 synchronized 的锁定,而且在代码执行时出现异常,JVM 会自动释放锁定,
lock 是通过代码实现的,要保证锁定一定会被释放,就必须将 unLock() 放到 finally{} 中;
3 在资源竞争不是很激烈的情况下,Synchronized 的性能要优于 ReetrantLock,
但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是 ReetrantLock 的性能能维持常态;