多线程笔记
synchronized 关键字
对某个对象加锁
public class T{
private int count = 10;
public void m(){
synchronized (this){
count--;
System.out.println(Thread.currentThread().getName() + "count = " + count);
}
}
}
等同于
public class T{
private int count = 10;
public synchronized void m(){
count--;
System.out.println(Thread.currentThread().getName() + "count = " + count);
}
}
知识点
- 同步方法和非同步方法可以同时调用
- 写方法加锁,读方法不加锁,会产生脏读问题
- 一个同步方法可以调用另一个同步方法,一个线程已经拥有某个对象的锁,再次申请的时候仍然会得到该对象的锁,也就是说synchronized获得的锁是可重入的(子类调用父类的同步方法也是可以的)
public class T{
synchronized void m(){
System.out.println("m start")
System.out.println("m end")
}
public static void main(String[] args) {
new TT().m();
}
}
class TT extends T{
synchronized void m(){
System.out.println("child start")
super.m();
System.out.println("child end")
}
}
- 程序在执行过程中,如果出现异常,默认情况锁会被释放,如果不想释放需要处理异常
- volatile 关键字 使一个变量在多个线程间可见
A B线程都用到一个变量,java默认是A线程缓冲区中保留一份copy,这样如果B线程修改了该变量,则A线程未必知道
在下面的代码中,running是存在于堆内存的t对象中,当线程t1开始运行的时候,running值从内存中读到t1线程的工作区,在运行过程中直接使用这个copy,并不会每次都去读取堆内存,这样当主线程修改running 的值后,t1线程感知不到,所以不会停止运行public class T{ volatile boolean running = true; void m(){ System.out.println("start"); while(running){ } System.out.println("end"); } public static void main(String[] args) { T t = new T(); new Thread(t::m,"t1").start(); try { TimeUnit.SECONDS.sleep(1); } catch(Exception e) { e.printStackTrace(); } t.running = false; } }