java多线程编程核心技术
2017-06-04 本文已影响26人
yueyue_projects
第一章:java多线程技能
开启线程
这里就不说了,有thread
和runnable
可以实现
停止线程
-
interrupt()
: 只赋值标志位,不真正停止线程,isInterrupted
测试线程Thread对象是否已经是中断状态,但不清楚状态标志。interrupted
测试主线程是否已经是中断状态,为静态函数,执行后清除标志位
public class MyThread extends Thread {
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
for(int i = 0; i < 10000; i++){
System.out.println("i=" + (i + 1));
}
}
//停止非主线程的方法,但没有真正停止
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
try {
Thread.sleep(10);
thread.interrupt();
System.out.println("是否停止1?" + thread.isInterrupted());
System.out.println("是否停止2?" + thread.isInterrupted());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("end!");
}
}
线程停止示意图
将
MyThread run()
换成如下代码段即可,此方法为异常停止法,一般都是用这种方法
public void run() {
// TODO Auto-generated method stub
super.run();
try {
for(int i = 0; i < 10000; i++){
if(this.isInterrupted()){
System.out.println("已经是停止状态,我要退出了");
throw new InterruptedException();
}
System.out.println("i=" + (i + 1));
}
} catch (InterruptedException e) {
// TODO: handle exception
System.out.println("进MyThread.java类run方法中的catch了");
e.printStackTrace();
}
}
执行结果:
Paste_Image.png
暂停线程
- 低端的方法用suspend和resume
线程的优先级
- 线程的优先级越高,占用的cpu资源就越多
守护线程
比如GC(垃圾回收器)就是守护线程。其满足一条性质即用户线程开启,则守护线程开启,关闭,则关闭
第二章:对象及变量的并发访问
synchronized关键字
- 局部变量即一个方法内的变量为线程安全因为每个线程执行时将会把局部变量放在各自栈帧的工作内存中,线程间不共享,故不存在线程安全问题。
- 全局变量因为是独一份,所以非线程安全
-
synchronized(this)
与synchronized(非this对象)
的分析
是什么?略过。 -
synchronized public void f1(){}
是锁定调用该方法的对象,``
synchronized(非this对象)的优势:
//阻塞了整个对象
synchronized void f1(){
//网络请求操作
...
}
synchronized void f2(){
//网络请求操作
...
}
分析知,当对象调用f1()的时候,f2()被阻塞,而
void f1(){
//网络请求操作
synchronized(非this对象)
...
}
synchronized void f2(){
//网络请求操作
synchronized(非this对象){
...
}
}
分析知,该情况f2()是不会阻塞的
- 结论
- A线程执行包含
synchronized(x)
的函数,非A线程执行x对象里的‘同步函数’时,呈同步效果
- A线程执行包含
class X{
void test(Y y){
synchronized(y){
...
}
}
}
class Y{
synchronized void f1(){
...
}
}
分析:当A正在执行test(Y y)
时,其他线程并不能执行f1()函数,因为 synchronized(y)锁住了y对象
- 不同的锁不会出现同步效果比如class锁(可以理解为静态锁独一份)和对象锁,其中class类锁的含义如下:
class X{
//f1(),f2()的调用后,他们的锁其实就是同一把(因为静态独一份)
synchronized public static void f1(){...};
synchronized public static void f2(){...};
// g1和g2的调用,锁的是其分别的调用对象实例,这两把锁是不同的
synchronized public void g1(){...};
synchronized public void g2(){...};
}
-
synchronized
关键字加到static
静态方法上是对Class类加锁,而加到非静态方法上是对调用该方法的对象实例加锁. - 一般synchronized代码块都不使用String作为锁对象,因为常量池的原因。
- 在一个
class
中的函数可能会有如下需求,有些方法需要彼此同步有些又不需要,我们可以使用如下方法解决问题
//假设f1()是一个类似监听的死循环(死循环根据其性质是不需要和任何方法同步的),f2(),f3()之间彼此需要同步,f4(),f5()也需要同步,而f2()与f4()之前不需要同步,因为极有可能会影响效率
class X{
f1(){...};
Object object1 = new Object();
f2(){
synchronized(object1){...}
};
f3(){
synchronized(object1){...}
};
Object object2 = new Object();
f4(){
synchronized(object2){...}
};
f5(){
synchronized(object2){...}
};
}
volatile关键字
- 核心:该关键字的作用是使变量在多个线程间可见
-
私有堆栈和公共堆栈理解如下图:
image.png
其中x=3是备份的,volatile关键字的作用就是强制从主存的公共堆栈里面取x的值
- volatile与synchronized的区别
- volatile更轻量
- volatile不能实现无原子性,当然肯定无法实现同步性,其只能保证多个线程间值的可见性,在宏观逻辑上使用只使用该关键字感觉是有问题的。synchronized是可以实现同步性的即保证了原子性和可见性
- synchronized可以实现volatile可见性的功能如下:
class X{
bool isTrue = true;
void f1(){
while(isTrue){
Object object = new Object
//该句话在内部将私有堆栈变量和公共堆栈变量进行同步啦,即将私有堆栈的变量写入公有堆栈
synchronized(object){
}
System.out.print("已经停止");
}
void setFalse(){
isTrue = false
}
}
}
第三章:线程间通信
等待/通知机制(关于wait和notify的一些应用)
基本使用
- (?理解可能有问题)调用wait()和notify()方法之前,线程必须获得该对象的对象级别锁,从下面的代码可以看到,两个都锁住了同一对象
lock
,但是并没有阻塞,是因为lock.wait()
交出了lock
锁且使处于临界区内的线程进入等待状态,但是只有notify
可以解密
public class MyThread1 extends Thread{
private Object lock;
public MyThread1(Object lock){
this.lock = lock;
}
@Override
public void run() {
// TODO Auto-generated method stub
synchronized (lock) {
try {
System.out.println("wait start");
lock.wait();
System.out.println("wait end");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class MyThread2 extends Thread{
private Object lock;
public MyThread2(Object lock){
this.lock = lock;
}
@Override
public void run() {
// TODO Auto-generated method stub
synchronized (lock) {
System.out.println("notify start");
lock.notify();
System.out.println("notify end");
}
}
}
public class Test {
public static void main(String[] args) {
Object lock = new Object();
MyThread1 thread1 = new MyThread1(lock);
MyThread2 thread2 = new MyThread2(lock);
thread1.start();
// try {
// Thread.sleep(2000);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
thread2.start();
}
}
output: wait start
notify start
notify end
wait end
- 临界区:一段只能被单个线程访问的区域,即当一个线程进入临界区,其他线程只能进入等待状态
- notifiy执行完后,不会释放锁,会在同步方法执行完后才释放锁
- 当interrupt方法遇到wait方法会导致线程终止
- 小总结:
- wait方法的作用:释放对象锁,且让线程进入线程等待池,等待被唤醒
- notify方法的作用:随机(这里也取决于线程的优先级)唤醒线程
- 生产者和消费者模式
- 一生产与一消费