《java多线程编程核心技术》

来源:互联网 发布:mathematics软件 编辑:程序博客网 时间:2024/06/05 07:20

window查看进程
1、打开CMD
2、进入JDK安装目录,进入bin目录
3、jps查看正在运行的线程号
4、jstack -l 查看进程具体内容

为什么要使用多线程
a、提高系统的吞吐率。可以有多个并发的操作,如I/O处理、访问数据库等耗时操作会释放CPU时间片,使CPU可以处理其他线程。
b.提高响应性。异步执行任务,将耗时的操作丢给其他工作者线程执行,调用可以很快的收到响应并执行其他操作。
c、充分利用多核CPU。随着现代CPU的生产工艺从CPU主频频率转向多核化,即在一块芯片上集成多个CPU内核,因此多线程编程充分利用计算机资源、提高软件服务质量。
d、最小化对系统资源的使用。一个进程中多个线程共享其所申请到的资源
e、简化程序的结构。能够将复杂耗时的任务分解成多个独立或半独立的任务同时执行。

缺点:
a、线程安全问题,多个线程共享数据可能导致读脏数据,丢失更新。
b、线程生命特征问题。可能产生死锁,或者线程一直尝试某个动作但就是无法进展,产生活锁现象。
c、上下文切换带来的性能开销。
d、可靠性。可能因内存泄漏导致JVM奔溃

1、进程和线程的区别
进程代表运行中的程序。一个运行的java程序就是一个进程,一个程序至少有一个进程,一个进程至少有一个线程。
从操作系统的角度来看,线程是进程中可独立执行的子任务。
进程是系统进行资源分配和调度的一个独立单位,一个进程可以包含多个线程,同一个进程中的线程共享该进程所申请到的资源,如内存空间和文件句柄等,从而极大地提高了程序的运行效率。
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间。
从JVM的角度看,线程是进程中的一个组件,他是执行java代码的最小单位。

2、创建一个线程类可以继承Thread或者实现Runnable接口
一般情况下是继承Thread,当线程类已经继承了其他类时只能实现Runnable接口。
JVM会为一个Thread分配2个调用栈所需的内存空间。一个调用栈跟踪java代码间的调用关系,另一个用于跟踪java代码对本地代码(即native代码)的调用关系

3、实例变量线程共享
new ThreadA().start() 不共享ThreadA中的变量
new Thread(threadA).start() ,共享变量放在线程threadA中, 如投票系统
4、Thread.currentThread().getName() 返回当前线程名称
5 isAlieve() 判断当前的线程是否处于活动状态。
6 getId() 获取线程的唯一ID
7 停止线程
stop(),不安全(释放锁),已被弃用,很暴力,需要手动做一些清理性工作
Thread.interrupt(),一般都用这个,但该方法只是标志一个中断的记号,并不会马上停止线程,并判断this.interrupted()。
this.interrupted() 测试当前线程是否已经中断,执行后具有将状态标志置清除为false
this.isInterrupt() 测试线程Thread对象是否已经中断, 不具有将状态标志置清除为false

try{    if(this.interrupted()){        throw new InterruptException();    }    ......}catch{}   这样就进入catch语句,运行下面的语句了Thread.interrupt()也能将睡眠中的代码或遇到sleep()、wait()后直接进入catch语句,并清除停止状态为false。

8 suspend/resume 暂停/重新启用线程,已被弃用,
不释放锁,造成资源浪费
不同步
9 yield() 放弃当前的CPU资源,将其让给其他线程
10 线程的优先级,优先级较高的线程会优获得更多的CPU资源,从而优先处理(并不一定,只是概率大些)。
线程优先级范围为1到10
优先级具有继承性,子线程的优先级和父线程一致
优先级有规则性,优先级高的大部分会先执行
优先级随机性,并不是优先级高的线程一定先执行
11 线程有2种,一种是用户线程,一种是守护线程。
当进程中不存在非守护线程时,守护线程会自动销毁,只要当JVM实例中存在任何一个非守护线程没有结束,守护线程就在工作,(举例:GC,垃圾回收器)
thead.setDaemon(true);
12 出现异常,锁会被自动释放
synchronized(this) 在同一个对象中都是同步的,是锁定当前对象。
synchronized同步方法和synchronized(this)调用呈阻塞状态
同一时间只有一个线程可以执行synchronized同步方法中的代码
同一时间只有一个线程可以执行synchronized(this)代码块中的代码
13 synchronized(非this对象x),x一定要是同一对象才会同步,特别注意String类型,不是equal就可以,必须是同一个地址的同一个对象
14 volatile 使变量在多个线程间可见,强制从公共堆栈中取得变量的值,而不是从线程私有数据栈中取得变量值。
volatile 不具备原子性, synchronized具备原子性,synchronized包含volatile功能,但效率较低。
synchronized包含互斥性和可见性。
线程安全包含原子性和可见性两个方面,Java同步机制都是围绕这两个方面来确保线程安全的。

volatile 的使用条件 —— 即变量真正独立于其他变量和自己以前的值    将 volatile 变量作为状态标志使用    将 volatile 变量用于一次性安全发布    将 volatile 变量用于多个独立观察结果的发布    遵守 volatile bean 模式的 Person 对象

1 wait()/notify()/notifyAll()
必须在synchronized同步的Object临界区中使用,否则会抛出 IllegelMonitorStateException.
每个Object都实现了wait()和notify()方法
wait()方法可以使调用该方法的线程释放共享资源的锁,然后从运行状态退出,进入等待队列,直到被再次唤醒。
notify()方法可以随机唤醒等待队列中等待同一共享资源的一个线程,并使该线程退出等待队列,进入可运行状态。
notifyAll()方法可以使所有正在等待队列中等待同一共享资源的 全部 线程从等待状态退出,进入可运行状态。此时,优先级高的那个线程最先执行

synchronized(a){    a.wait();}

2 IO阻塞、访问其他服务器、数据库、线程CPU处于空闲状态,可能会转而把CPU时间片分配给其他线程,进入 暂停状态。 阻塞(Blocked)状态结束后,进入runnable状态,等待系统重新分配资源。
3 线程出现阻塞的情况
调用sleep(),主动放弃占有的处理器资源。
调用了阻塞式IO方法,未返回。
试图获得一个同步监控器(锁资源),但监控器被其他线程占有。
线程等待某个通知
调用suspend方法将线程挂起,此方法容易导致死锁。
4 线程进入Runnable的情况
调用sleep(),已超过休眠时间。
调用了阻塞式IO方法,IO执行完毕。
成功获得一个同步监控器(锁资源)。
线程等待某个通知,其他线程发出了通知。
处于挂起状态的线程调用了resume()回复方法。
5 每个锁对象都有2个队列,一个就绪队列,一个阻塞队列。就绪队列存储将要获得锁的线程,阻塞队列存储被阻塞的线程线程被唤醒进入就绪队列等待CPU的调度,线程被wait后进入阻塞队列等待被唤醒
6 wait方法被执行后自动释放锁,notify()被执行后不自动释放锁。
7 wait(long) 等待某一时间内是否有线程对锁进行唤醒,如果超过这个时间则自动唤醒。
8 threadA.join() 等待threadA线程运行完销毁后再运行当前线程,具有使线程排队运行的作用,join在内部使用了wait()方法进行等待。
9 join(long)内部使用了wait(long),会释放锁,sleep(long)不会释放锁。

1 ReentrantLock , Lock对象里面可以创建多个Condition(即对象监听器)实例,线程对象可以注册到指定的Condition中,从而可以有选择性的进行线程通知。
相比wait() notify() notifyAll()在JVM中随机选择,Lock Condition可以选择性通知。
2 Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
使用condition.wait(), condition.signal(), condition.signalAll()方法之前必须先调用 lock.lock()
3 Lock分为公平锁和非公平锁
公平锁:Lock lock = new ReentrantLock(true),线程获取锁的顺序按照加锁的顺序来分配的,即FIFO
非公平锁:Lock lock = new ReentrantLock(false),线程获取锁的顺序是随机抢占的
4 int getHoldCount() 查询当前线程保持此锁定的个数,也就是调用lock()方法的次数
int getQueueLenght() 返回正等待获取此锁的线程数
int getWaitQueueLenght(Condition condition) 返回condition等待此锁的线程数
boolean isFair() 判断是不是公平锁
boolean isLocked() 判断是否被任意线程锁住
void lockInterrupbtibly() 如果当前线程未被中断,则获取锁定,如果已被中断则抛出异常
boolean tryLock() 紧在其他线程未保持锁定状态时才可以获得锁
boolean tryLock(long timeout, TimeUnit unit) 在等待的时间内,其他线程未保持锁定状态,且当前线程未被中断,则获得该锁定。
5 ReentrantReadWriteLock 读写锁
对于写操作较少,读较多的线程效率会大大提高。
表示有2把锁,读锁、写锁,多个读锁之间不互斥,读锁与写锁互斥,写锁与写锁互斥。

原创粉丝点击