java多线程编程
第一章:
实现多线程编程主要有两种方式,一种是继承Thread类,另一种是实现Runnable接口。
使用继承Thread类的方式创建新线程时,最大的局限就是不支持多继承,因为java语言特点就是单继承,所以为了支持多继承完成可以实现Runnable接口的方式,一边实现一边继承。这两种方式创建的线程在工作时的性质是一样的,没有本质上的区别。
在源码中 public class Thread implements Runnable 可以发现,Thread类实现了Runnable接口,他们之间具有多态的关系
start()方法和run()方法的区别
Thread.java类中的start()方法通知“线程规划器”,此线程已经准备就绪,等待cpu调用线程对象的run(),使线程等到运行,这个过程其实就是让系统安排一个时间调用Thread中的run方法,具有异步的效果
如果调用thread.run(),直接调用run方法的话就不是异步执行了,而是同步。那么这个线程对象就没有交给线程规划器来处理,而是由main主线程来调用run方法,也就是必须等待run()方法中的代码执行完毕才可以执行后面的代码
另外还要注意,启动start()方法的顺序不代表线程启动的顺序
第二章:
"非线程安全问题":在多个线程对同一对象中的实例变量进行并发访问时发生,产生的后果就是"脏读"
"脏读":读取得的数据其实就是被更改过的,发生脏读的情况就是读取实例变量时,此值被其他线程修改过了
"线程安全":就是以获取的实例变量的值是经过同步处理的,不会出现脏读的现象。
"非线程安全"问题存在于"实例变量"中,如果是方法内部的私有变量,则不存在"非线程安全"问题,所得的结果也就是"线程安全"的
如果两个线程同时访问一个没有同步的方法,两个线程同时操作业务对象中的实例变量时,就有可能出现"非线程安全问题"
两个线程访问同一对象中的同步方法一定是线程安全的。
同步方法就是加了synchronized字眼的方法
关键字synchronized取得的锁都是对象锁,而不是把一段代码或者方法(函数)当作锁,
哪个线程先执行带synchronized关键字的方法,哪个线程就持有该方法所属对象的锁,那么其他的线程只能呈等待状态,前提是多个线程访问的是同一对象
如果是多个线程访问多个对象,则JVM会创建多个锁。各个锁是相互独立的。
可重入锁:自己可以再次获取自己的内部锁。比如一个对象有一个同步方法,该A同步方法里面还有一个B同步方法,这时候想执行里面的B同步方法时,就不需要等待A方法执行完毕。B同步方法可以直接执行
异常释放锁:当两个线程访问同一对象的同一同步方法,其中第一个线程进去的了该同步方法,但是出现了异常,该线程就会马上释放锁,第二个线程就会立即等到这个锁
java还支持对"任意对象"作为"对象监视器"来实现同步的功能。这个"任意对象"大多数是实例变量及方法的参数,使用的格式是 synchronized(非this对象)
1.在多线程持有"对象监视器"为同一个对象的前提下,同一时间只有一个线程可以执行synchronized(非this对象) 中的代码
2.
私有变量是线程安全,实例变量是非线程安全