6线程停止:
Thread类的stop方法不能再用了,应当然线程自然结束,两种方式:
1MyThread extends Thread{boolean flag=true;
@Override
run(){while(flag){要执行的代码}}死循环一直执行;
stopThread(){flag=true;}}自己提供的方法,终止线程运行;
2或者
run(){while(flag){if(结束条件满足) {return;}要执行的代码}}如果满足条件就自动终止线程。
7线程同步:1多线程共用同一资源时(同一Runnble对象或同一其他类的对象),保证操作的原子性或事务性,变成同步资源。2一旦线程访问同步资源为该资源加锁(monitor),其他线程不能访问,执行完资源后释放锁。3两种形式:1synchronize int 方法名() 锁方法所在对象2方法里面加synchronize(对象引用)块,锁指定对象!
3每个对象都有一把锁(monitor)上锁是对 对象上锁!!包含该synchronize 方法或代码的对象上锁,所以当一个对象有多个synchronize 方法或块时,只要其中一个被线程访问,对象会上锁,其他synchronize 方法或块也不能被其他线程访问。
4关键是要搞清楚给哪个对象上了锁,已经有几个对象!
5当synchronized修饰的是类的静态方法时,会锁该类的Class对象,因为所有对象只有一个Class对象,因此即使不共用对象,也会保证静态方法的原子性!
6当一个类中一个synchronized修饰静态方法,一个修饰动态方法时,分别会锁类的Class对象和类的对象,互不影响,因为锁的两个不同对象。
7synchronized里的成员变量,要保证是private的,为了防止在synchronized之外也能访问,就不会再同步了。
1例:为了保证取款过程的原子性!防止读脏。对线程所调用的方法声明为synchronized
class Bank{private int money=1000;Bank对象或money属性是公共资源
public synchronized int getMoney(int num){money-=num; return num;}}
保证同一时间只能有一个线程访问此方法!
class MyThread extends Thread{
private Bank b; 线程操作账户,需要账户对象引用
public Mythread(Bank b){this.b=b}
run(){b.getMoney(800);}}
main(){Bank b=new Bank();
Thread t1=new MyThread(b);t1.start();公用同一Bank对象的money属性。
Thread t2=new MyThread(b);t2.start();}
8synchronized静态代码块,放在方法内,更加细粒度,效率更高,很常用!
class Resource{private String s=new String();成员变量
private Object o=new Object();
synchronized(o){代码}}
synchronized(this){代码}甚至synchronized(s),都可以,可以是任意一个对象,但必须保 证对象唯一。每一个Rresource对象只对应一个Object对象,一个String对象属性。
9Thread的sleep方法只是暂停线程失去cpu,但不失去锁!!sleep的作用可以调节线程执行的快慢。
同步是重量级的,效率太低了,等待时间会很长
7线程生命周期
1new是创建状态 2 start以后是可运行状态 3可运行状态获得cpu变成运行中状态4运行中的线程如果需要执行io操作,或调用sleep方法,会失去cpu变成阻塞状态 5run方法结束,包括不正常结束:抛异常,线程会停掉。
8线程优先级:1子线程和他的父线程拥有相同的优先级,就像main方法里new一个线程,则该线程和主线程优先级相同!2如果一个正在运行的线程,遇到或new出一个优先级更高的线程,会将cup让个优先级高的线程!
3Thread有setPriority方法,从1到10改变优先级,还有三个常量MAX-PRIORITY为10,MIN-PRIORITY为1,NORMAL-PRIORITY为5 是线程默认优先级,不要直接设置数字,因为不同系统的线程优先级不同,最常用是设置三个常量!优先级高的线程会获得更多的执行机会!但会导致优先级低的线程永远得不到执行,仅仅靠优先级,不能很好控制线程,需要配合线程调度策略!
9线程同步:让线程协同完成工作,让多个synchronized块有先后顺序的执行!
1deadlock死锁:两个线程,每个线程同时需要A,B两个资源才能完成任务,但各自拥有一个资源,各自不会将自己资源给对方。
Object类的一些方法:来控制公共资源的锁在线程间的传递,会抛出异常,需要处理。
1wait():条件是:让当前线程wait,醒来后继续执行剩下代码!条件是:当前线程已经拥有了lock,说明一定在synchronized块里,因此wait()方法的调用也一定要在synchronized块里!!
2notify():从wait状态的多个线程里随机唤醒一个线程!并释放lock,条件是:该线程必须已经拥有锁,说明一定在synchronized块里,因此notify()方法的调用也一定要在synchronized块里!!
3wait和notify方法在两个synchronized块中一定要成对存在,且一定要在synchronized块里出现!!且调用notify和wait方法的对象都是同一个synchronized的对象(上锁的对象)。wait是让当前获得锁的线程,丢掉锁给其他线程。notify是从执行这两个synchronized块的所有的wait的线程池里唤醒一个线程,让它继续执行,并将锁给它,如果没有wait线程,只释放锁。
4例子:一个类的成员变量初始0,一个线程+1,一个线程-1,打印010101...
1 class Sample{private int num;
1 public synchronized void increase(){
if(0!=num){wait();}让当前线程wait,与下面synchronized块的notify对应
num++;print(num);
notify(); 该轮到其他线程工作了,通知其他线程,释放锁!与下面synchronized块的wait对应
2public synchronized void decrease(){
if(1!=num){wait();}让当前线程wait,与上面synchronized块的notify对应
num--;print(num);
notify(); 该轮到其他线程工作了,通知其他线程,释放锁!与上面synchronized块的wait对应
3定义两个线程:
class IncreaseThread extends Thread{
private Sample s;线程要操作类,保留引用
public IncreaseThread(Sample s){this.s=s;}
run(){for(int i=0;i<0;i++){s.increase();}}打印10次
class DecreaseThread extends Thread{
private Sample s;线程要操作类,保留引用
public IncreaseThread(Sample s){this.s=s;}
run(){for(int i=0;i<0;i++){s.decrease();}}打印10次
4 main(){
1 Sample s=new Sample();
Thread t1=new IncreaseThread(s);t1.start();
Thread t2=new DecreaseThread(s);t2.start();
会交替执行Sample的两个synchronized方法!
2如果再加入两个线程:多个线程的通信
Thread t3=new IncreaseThread(s);t3.start();
Thread t4=new DecreaseThread(s);t4.start();
就会混乱了,因为有可能Increase的线程会notify唤醒另一个wait的Increase的线程,会出现,连续执行increase的现象,出现大于一的数
改进:被唤醒后的线程应当,再次判断num的值,如果不符合,就继续wait
public synchronized void increase(){
if(0!=num){wait();}(只判断一次,只执行一次wait)改为:
while(0!=num){wait();}循环执行wait直到num值满足条件,每次执行完wait都会判断
num++;print(num);}
|
|