多线程同步

java.lang.Thread 此类是Java中多线程的核心类
--------------------Java多线程实现--------------------
无论使用哪种方式创建线程,启动线程一律使用Thread类提供的start()方法。用户不能直接调用run()

!!!!start():同步方法
一个线程的start()只能被执行一次,执行多次会抛出IllegalThreadStateException异常
start()方法刚开始会判断线程状态(默认是0)
调用start0()方法:被native修饰(本地方法,调用C语言方法)
进入JVM中,创建线程,而后执行线程任务
a.继承Thread类,而后覆写run():线程任务方法,在Runnable接口里的方法,Thread类也实现了Ruannble接口
b.实现Runnable接口,而后覆写run(),通过Thread类的有参构造方法:Thread(Runnable target)<实现了Runnable接口的实例化对象>;
实现Runnable接口,可更好的实现程序共享的概念

class Mythread implements Runnable{
    private int ticket = 20;
    public void run(){
        while(ticket>0){
            System.out.println("当前线程为:"+Thread.currentThread().getName()+"票数:"+ticket--);
        }
    }
}
public class Test{
    Mythread mt1 = new Mythread();//只创建了一个自己的线程类实例化对象
    Thread thr1 = new Thread(mt1);
    Thread thr2 = new Thread(mt1);
    Thread thr3 = new Thread(mt1);
    thr1.start();
    thr2.start();
    thr3.start();
}

上述为何是共同买票,是因为传入的线程对象所拥有的私有属性是一致的;而线程类所传入的属性是各线程各自拥有的私有属性
c.实现Callable接口,带有返回值覆写call()方法。
d.线程池
接口:ExecutorService:普通线程池
   -子类ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue workQueue
                           RejectedExecutionHandler handler)
   
!!!!!!!!!线程池工作流程
当一个任务提交给线程池时,
《1》首先判断核心池的线程数量是否达到corePoolSize,若未达到,线程池创建新的线程执行任务并将其置入核心池中。
    否则,判断核心池是否有空闲线程,若有,分配任务执行
《2》判断当前线程池中线程数量有没有达到线程池的最大数量,若没有,创建新的线程执行任务并将其置入线程池中
《3》判断阻塞队列是否已满,若未满,将任务置入阻塞队列中等待调度
《4》调用相应的拒绝策略,默认抛出异常给用户AbortPolicy
(1)核心线程池
(2)最大线程池
(3)阻塞队列
(4)打回策略
   -void execute(Runnable command);
   -Future submit(Callable task||Runnable)
ScheduledExecutorService:定时线程池

同步指的是所有的线程不是一起进入到方法中执行,而是按照顺序一个一个进来。
转账的例子:A->B 100 A-=100  B+=100
如何保护有关联关系的对象:使用同一把锁
如何保护毫无关系的对象:使用多把锁

public void zhuanzhang(Account target){
    synchronized(Account.class){
        this.sal -= 100;
        target.sal += 100;
    }
}


由于转账涉及两个账户间的sal的操作,因此将两个账户同时锁定。
synchronized()只能锁一个对象,因此锁不住转账操作


synchronized(this)以及非static的synchronized方法,只能防止多个线程同时执行同一个对象的同步
代码段。即synchronized锁住的是括号里的对象,而不是代码。对于非static的synchronized方法,锁的就是对
象本身也就是this。

synchronized 底层实现:
在使用synchronized时必须保证锁定对象必须为Object以及其子类对象
synchronized 使用的是JVM层级别的MonitorEnter与MonitorExit实现

这两个指令必须获取对象的同步监视器Monitor


对象锁Monitor机制
synchronized(O){}
(1)monitorenter:检查o对象的Monitor计数器值是否为0,为0表示此监视器还未被任意一个线程获取,线程可进入同步代码块并且将mintor值+1,
将monitor的持有线程标记为当前线程
(2)当Mnitor计数器值不为0时且持有线程不是当前线程,表示Monitor被别的线程占用,当前线程只能阻塞等待
(3)可重入锁:当执行MonitorEnter时,对象的Monitor计数器值不为0,但是持有线程恰好是当前线程。此时将Monitor计数器值再次+1,
当前线程继续进入同步方法或代码块

monitorexit:

1. 执行同步代码块后首先要先执行monitorenter指令,退出的时候monitorexit指令。通过分析之后可以看出,使用
Synchronized进行同步,其关键就是必须要对对象的监视器monitor进行获取,当线程获取monitor后才能继续往
下执行,否则就只能等待。而这个获取的过程是互斥的,即同一时刻只有一个线程能够获取到monitor。
JVM要确保所获得的锁在正常执行路径,以及异常执行路径上都能够被解锁。
2. synchronized 标记方法时,字节码中方法的访问标记包括ACC_SYNCHRONIZED.该标记表示在进入该方法时。JVM需要进行monitorenter操作

 

 

 

 

你可能感兴趣的:(JavaSE)