700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > java多线程核心技术_Java多线程编程核心技术(笔记)

java多线程核心技术_Java多线程编程核心技术(笔记)

时间:2024-02-11 14:05:37

相关推荐

java多线程核心技术_Java多线程编程核心技术(笔记)

方法内部的私有变量,不存在线程安全问题,永远都是线程安全的,这是方法内部的变量是私有的特性造成的。

实例变量非线程安全,多个线程访问同一个对象的实例变量,则有可能出现非线程安全问题。

synchronized取得的是对象锁,而不是把一段代码或者一个方法当做锁。

调用synchronized的方法一定是排队运行的

A线程先持有object对象的Lock锁,B线程可以以异步的方式调用object对象中的非synchronized类型的方法

A线程先持有object对象的lock锁,B线程如果在这时调用object对象中的synchronized类型的方法,则需要等待,也就是同步。

一个对象的多个synchronized方法有唯一的对象锁

增加了synchronized的方法一定是同步执行的,例如对象A执行完后synchronized方法后,才可执行对象A的其他synchronized方法。或者说在执行一个对象中的synchronized方法时,必须等待该方法执行完毕。

synchronized锁可重入:对象A的synchronized方法可以调用A对象中的其他synchronized方法。

锁重入也适用于父子类关系的synchronized方法调用

synchronized出现异常时,会自动释放锁

synchronized同步不具有继承性,因此对象A不能继承父类的synchronized方法

同一个对象中的不同synchronized代码块,使用的是同一个锁。

同一个对象中的synchronized代码块与synchronized方法使用的是同一个锁

synchronized代码块参数可以使用非this参数,即可以使用对象的变量或者方法的参数(变量必须是对象的变量,不能是方法内的局部变量)

同一个对象中方法A的synchronized方法与方法B的(非this参数)synchronized代码块线程是非安全的

synchronized加在static静态方法上时,是对类进行加锁,而synchronized加载非static方法上时,是给对象上锁

synchronized代码块中参数为非this参数时,如果一个对象中的有两个方法中各自有一个代码块并且参数不为this,则这两个方法执行时为异步方式,即两个线程调用两个方法时,两个方法同时执行。

volatile关键字的作用是强制从公共堆栈中取得变量的值,而不是从线程私有数据栈中取得变量的值。

使用volatile关键字增加了实例变量在多个线程之间的可见性,但是volatile关键字不支持原子性。

关键字volatile是线程同步的轻量级实现,所有volatile性能肯定比synchronized要好,并且volatile只修饰变量,而synchronized可以修饰方法、代码块。

多线程访问volatile不会发生阻塞,而synchronized会发生阻塞。

volatile能保证数据的可见性,但不能保证原子性了,而synchronized可以保证原子性,也可以间接保证可见性,因为它会将私有内存和公共内存中的数据做同步。

volatile关键字用于解决变量在多线程之间的可见性。

synchronized关键字解决的事多线程之间访问资源的同步性。

关键字synchronized可以使多个线程访问同一个资源具有同步性,而且他还具有将线程工作内存中的私有变量与公共内存中的变量同步的功能。

sleep与yield是Thread的方法

wait与notify是object类的方法

wait释放锁,notify锁不释放

notify操作会试图唤醒一个因调用wait操作而除去阻塞状态中的线程,如果没有处于阻塞状态的线程,则该命令会被忽略。

wait方法会使调用该方法的线程释放共享资源所,然后从运行状态退出,进入等待队列,直到被再次唤醒。

wait与notify必须在synchronized同步方法或者同步块中调用,如果调用notify与wait是没有持有锁,则报错,notify方法执行后,当前线程不会马上释放该对象 锁,同时wait状态的线程也不能马上获得对象的锁,要等到notify方法的线程执行完后,才会释放对象锁。

每个锁对象有两个队列,一个是就绪队列(存储将要获得锁的线程),一个是阻塞队列(存储被阻塞的线程),wait与notify可以是线程在就绪队列与阻塞队列之间转换。

通过通道进行线程间的通讯:字节流,调用完毕后,需要执行close关闭方法。

PipeInputStream、PipeOutStream

PipeWrite、PipeRead

方法join的作用是等待线程对象销毁。

在调用join的过程中,如果当前线程对象中断了,则当前线程出现异常。

join方法在内部使用了wait方法进行等待,而synchronized关键字使用的是"对象监视器"原理做的他同步。

方法join可以使所属的线程对象X正常执行run方法中的任务,而使当前线程x进行无限期的阻塞,等待线程x销毁后再继续执行线程z后面的代码。

join(Long)设定等待时间

join与sleep区别:join方法内部使用了wait方法来实现,所有join方法具有释放锁的特定。而Thread.sleep()方法不能释放锁。

ThreadLocal:主要解决的就是每个线程绑定自己的值,可以将ThreadLocal类比喻成全局存储数据的盒子,盒子中可以存储每个线程的私有数据。

多个线程中各自线程设置的ThreadLocal变量是独立的。

InheritableThreadLocal可以在子线程中获得父线程中设置的InheritableThreadLocal值。

如果需要在子线程中对父线程中获得的值就行修改,可以继承InheritableThreadLocal类,同时在childValue方法对父类中获得的值进行修改。

但是需要注意的是,如果子线在获取父类InheritableThreadLocal值得时候,父线程对值进行了更改,那么子线程获取的InheritableThreadLocal值还是旧值。

ReentrantLock

调用ReentrantLock对象的lock()方法获得锁,调用unlock方法释放锁。

lock方法的线程持有的是“对象监视器”

ReentrantLock使用Condition实现等待与通知。

synchronized的线程执行notifyAll时,需要通知所有waiting的线程。没有选择权,会出现相当大的效率问题。

Condition对象调用await()方法之前,必须执行ReentrantLock对象的lock方法,否则会报错。(即必须获得“同步监视器”后才可以执行await方法)

Condition类的signal与await相对应。类似于Object类的wait与notify。

如果一个ReentrantLock类获得多个Condition对象,可以根据Condition不同等待或者唤醒指定的Condition对象。

公平锁与非公平锁

锁Lock 分为公平锁与非公平锁。公平锁便是线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先得的FIFO先进先出顺序,而非公平锁就是一种获取锁的抢占机制,是随机获取锁的,和公平锁不一样的是就是先来的不一定先得到锁,这个方式可能造成某些线程一直拿不到锁,结果也就是不公平了。

ReentrantLock通过构造参数设置公平锁与非公平锁,默认为公平锁,而ReentrantLock(false)为非公平锁。

ReentrantLock类的getHoldCount方法作用是查看当前线程保持次锁定的个数,也就是调用lock方法的次数(针对于lock嵌套即A方法中有lock方法,同时A方法调用了B方法,同时B方法中也调用了lock的方法,在A方法中getHoldCount返回1,在B方法中getHoldCount返回2)

ReentrantLock类的getQueueLength方法作用是返回正等待获取此锁的线程计数器。

ReentrantLock类的getWaitQueueLength(Condition condition)的作用是返回等待与此锁相关的给定条件Condition的线程估计数,比如有5个线程,每个线程都执行了同一个Condition对象的await方法,则调用getWaitQueueLength方法时返回int值为5.

hasQueueThread作用是查询指定的线程是否正在等待获取此锁定。

hasQueueThreads作用是查询是否有线程正在等待获取此锁定。

hasWaiters作用是查询是否有线程正在等待与此锁有关的Condition条件。

isFair()判断是否是公平锁

isHeldByCurrentThread()查看当前线程是否保持此锁定。

isLocked作用是查询此锁定是否有任意线程保持。

void lockInterruptibly()的作用是:如果当前线程未被中断,则获取锁定,如果已经被中断(即线程调用了interrupt方法)则返回异常。

boolean tryLock()方法作用是仅在调用时锁定未被另一个线程保持的情况下,才获得该锁定。

awaitUntil(Calendar.getTime())作用是等待到达指定时间,在开始执行之后的代码,该方法可以被notify或者notifyAll唤醒,即未到达指定时间也可以获得锁,继续执行后续代码。

ReentrantReadWriteLock类的多个读线程可以共享锁,但是只要多个线程中有一个写线程,则所有线程就是互斥锁。

Timer定时器

public classTest {public static class TaskService extendsTimerTask {

@Overridepublic voidrun() {

System.out.println("开始运行"+System.currentTimeMillis());

}

}public static void main(String[] args) throwsParseException {//Timer timer = new Timer();

Timer timer = newTimer();

SimpleDateFormat simpleDateFormat= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

TaskService taskService= newTaskService();

timer.schedule(taskService,simpleDateFormat.parse("-02-27 22:13:10"));

}

}

计划运行时间早于当前时间,则立即执行Task任务。

TimerTask是以队列的方式一个一个被顺序执行的,所以执行的时间有可能和预期的时间不一致,因为前面的任务有可能消耗的时间比较长,则后面的任务运行的时间也会被延期。

schedule(TimerTask task,Date firstTime,long period)方法的作用是在指定日期后,按指定的时间间隔周期性的无限循环地执行某一任务。 period参数为间隔时间(毫秒)

TimerTask类的cancel方法作用是将自身从任务队列中清除。其他任务不受影响。

public classTest {public static class TaskServiceA extendsTimerTask {

@Overridepublic voidrun() {

System.out.println("A开始运行"+System.currentTimeMillis());this.cancel();

}

}public static class TaskServiceB extendsTimerTask {

@Overridepublic voidrun() {

System.out.println("B开始运行"+System.currentTimeMillis());

}

}public static void main(String[] args) throwsParseException {//Timer timer = new Timer();

Timer timer = newTimer();

SimpleDateFormat simpleDateFormat= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

TaskServiceA taskServiceA= newTaskServiceA();

timer.schedule(taskServiceA,simpleDateFormat.parse("-02-27 22:13:10"),1000);

TaskServiceB taskServiceB= newTaskServiceB();

timer.schedule(taskServiceB,simpleDateFormat.parse("-02-27 22:13:10"),1000);

}

}

A开始运行1488209066938

B开始运行1488209066939

B开始运行1488209067939

B开始运行1488209068965

B开始运行1488209069965

B开始运行1488209070965

.....

Timer类的cance方法作用是将任务队列中的全部任务清空。

public classTest {public static Timer timer = newTimer();public static class TaskServiceA extendsTimerTask {

@Overridepublic voidrun() {

System.out.println("A开始运行"+System.currentTimeMillis());

timer.cancel();

}

}public static class TaskServiceB extendsTimerTask {

@Overridepublic voidrun() {

System.out.println("B开始运行" +System.currentTimeMillis());

}

}public static void main(String[] args) throwsParseException {//Timer timer = new Timer();

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

TaskServiceA taskServiceA= newTaskServiceA();

timer.schedule(taskServiceA,simpleDateFormat.parse("-02-27 22:13:10"),1000);

TaskServiceB taskServiceB= newTaskServiceB();

timer.schedule(taskServiceB,simpleDateFormat.parse("-02-27 22:13:10"),1000);

}

}

A开始运行1488209178347

Timer类的cance方法作用是将任务队列中的全部任务清空,但是有时候并不一定会停止执行计划任务,而是继续正常执行任务,原因是Timer的cancel方法并没有获得queue锁。

源码:

public voidcancel() {synchronized(queue) {

thread.newTasksMayBeScheduled= false;

queue.clear();

queue.notify();//In case queue was already empty.

}

}

schedule(TimerTask task,long delay)方法的作用是在当前的时间为参考时间,在此时间基础上延迟指定的毫秒数后执行一次TimerTask任务。

方法schedule与scheduleAtFixRate方法都是按顺序执行的,不需要考虑非线程安全问题

方法schedule与scheduleAtFixRate方法主要区别只在于不延时的情况。

方法schedule如果执行任务的时间没有被延时,那么下一次任务的执行时间参考的是上一次任务的开始时间来计算。

scheduleAtFixRate方法如果执行任务的时间没有被延时,那么下一次任务的执行时间参考的是上一次任务的结束时间来计算。

Thread.sleep()方法执行后,进入TIMED_WAITING状态

BLOCKED阻塞状态出现在某一个线程在等待锁的时候。

WAITING状态是Object.wait()方法后所处的状态

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。