黑马程序员——java语言基础部分——线程
2015-05-22 18:13
429 查看
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
概述:
进程:是一个正在执行中的程序
线程:是进程中的一个独立的控制单元。
注意:
一个进程中至少有一个线程。
Java VM 启动的时候会有一个进程java.exe。该进程中至少一个线程负责java程序的执行。而且这个线程运行的代码存在于main方法中。该线程称之为主线程。
jvm启动不止一个线程,还有负责垃圾回收机制的线程。
子类徐覆盖类中的run方法,将线程运行的代码存放在run中
简历子类对象的同时线程也被创建
通过调用start方法开启线程
2、实现Runnable接口
子类覆盖接口中的run方法
通过Thread类创建线程,并将实现了Runnable接口的子类对象作为参数传递给Thread类的构造函数
Thread类对象调用start方法开启线程
获取:
long getId() 返回该线程的标识符。
String getName() 返回该线程的名称。
int getPriority() 返回线程的优先级。
Thread.State getState()
返回该线程的状态。
String toString() 返回该线程的字符串表示形式,包括线程名称、优先级和线程组。
判断:
static boolean interrupted() 测试当前线程是否已经中断。
boolean isAlive() 测试线程是否处于活动状态。
boolean isInterrupted() 测试线程是否已经中断。
中断:
void interrupt() 中断线程。
static void yield() 暂停当前正在执行的线程对象,并执行其他线程。
加入:
void join()等待该线程终止。
void join(long millis)等待该线程终止的时间最长为 millis 毫秒。
void join(long millis, int nanos)等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。
注意:假如当A线程执行到了B线程的.join()方法时,A就会等待。等B线程都执行完,A才会执行
设置:
void setName(String name)
改变线程名称,使之与参数 name 相同。
void setPriority(int newPriority)更改线程的优先级。
void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)设置该线程由于未捕获到异常而突然终止时调用的处理程序。
休眠:
static void sleep(long millis)在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
static void sleep(long millis, int nanos)在指定的毫秒数加指定的纳秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
运行:
void start() 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
创建——》运行:start()方法
运行——》冻结:sleep(),interrupt()
冻结——》运行:notify(),notifyAll()
总结:notify()唤醒的是对应的中断的线程,notifyAll()唤醒的是所有处于冻结状态的线程。
多个线程访问出现延迟
线程随机性。
解决方案:同步
两个或者两个以上的线程
多个线程使用的是同一个锁
同步弊端:线程多时,对于同步上锁的判断会消耗很多的哦资源,降低运行效率
同步格式:
Synchronized(对象){
同步代码
}
同步的关键,控制共享的部分,即锁。
同步的锁:
同步代码的锁是object
同步函数的锁是this。因为函数的调用者是对象。
静态的同步函数的锁是类的字节码文件。因为静态函数在方法区中,是随着类的加载而加载的。
关于同步的思考思路总结:
明确哪些代码是多线程运行代码。
明确共享数据。
明确多线程运行代码中哪些语句是操作共享数据的。
参考代码
Condition 实例实质上被绑定到一个锁上。要为特定 Lock 实例获得 Condition 实例,请使用其 newCondition() 方法。
常用方法:
void await() 造成当前线程在接到信号或被中断之前一直处于等待状态。
void signal() 唤醒一个等待线程。
void signalAll() 唤醒所有等待线程。
ReentrantLock 将由最近成功获得锁,并且还没有释放该锁的线程所拥有。当锁没有被另一个线程所拥有时,调用 lock 的线程将成功获取该锁并返回。如果当前线程已经拥有该锁,此方法将立即返回。可以使用 isHeldByCurrentThread() 和 getHoldCount() 方法来检查此情况是否发生。
此类的构造方法接受一个可选的公平 参数。当设置为 true 时,在多个线程的争用下,这些锁倾向于将访问权授予等待时间最长的线程。否则此锁将无法保证任何特定访问顺序。与采用默认设置(使用不公平锁)相比,使用公平锁的程序在许多线程访问时表现为很低的总体吞吐量(即速度很慢,常常极其慢),但是在获得锁和保证锁分配的均衡性时差异较小。不过要注意的是,公平锁不能保证线程调度的公平性。因此,使用公平锁的众多线程中的一员可能获得多倍的成功机会,这种情况发生在其他活动线程没有被处理并且目前并未持有锁时。还要注意的是,未定时的
tryLock 方法并没有使用公平设置。因为即使其他线程正在等待,只要该锁是可用的,此方法就可以获得成功。
获取锁的方法是: void lock()
获取condition实例方法: Condition newCondition()。
使用lock机制的参考代码:
概述:
进程:是一个正在执行中的程序
线程:是进程中的一个独立的控制单元。
注意:
一个进程中至少有一个线程。
Java VM 启动的时候会有一个进程java.exe。该进程中至少一个线程负责java程序的执行。而且这个线程运行的代码存在于main方法中。该线程称之为主线程。
jvm启动不止一个线程,还有负责垃圾回收机制的线程。
创建线程方式
1、继承Thread类子类徐覆盖类中的run方法,将线程运行的代码存放在run中
简历子类对象的同时线程也被创建
通过调用start方法开启线程
2、实现Runnable接口
子类覆盖接口中的run方法
通过Thread类创建线程,并将实现了Runnable接口的子类对象作为参数传递给Thread类的构造函数
Thread类对象调用start方法开启线程
Thread类
常用方法:获取:
long getId() 返回该线程的标识符。
String getName() 返回该线程的名称。
int getPriority() 返回线程的优先级。
Thread.State getState()
返回该线程的状态。
String toString() 返回该线程的字符串表示形式,包括线程名称、优先级和线程组。
判断:
static boolean interrupted() 测试当前线程是否已经中断。
boolean isAlive() 测试线程是否处于活动状态。
boolean isInterrupted() 测试线程是否已经中断。
中断:
void interrupt() 中断线程。
static void yield() 暂停当前正在执行的线程对象,并执行其他线程。
加入:
void join()等待该线程终止。
void join(long millis)等待该线程终止的时间最长为 millis 毫秒。
void join(long millis, int nanos)等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。
注意:假如当A线程执行到了B线程的.join()方法时,A就会等待。等B线程都执行完,A才会执行
设置:
void setName(String name)
改变线程名称,使之与参数 name 相同。
void setPriority(int newPriority)更改线程的优先级。
void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)设置该线程由于未捕获到异常而突然终止时调用的处理程序。
休眠:
static void sleep(long millis)在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
static void sleep(long millis, int nanos)在指定的毫秒数加指定的纳秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
运行:
void start() 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
线程的状态
线程有四种状态:创建,运行,冻结,消亡创建——》运行:start()方法
运行——》冻结:sleep(),interrupt()
冻结——》运行:notify(),notifyAll()
总结:notify()唤醒的是对应的中断的线程,notifyAll()唤醒的是所有处于冻结状态的线程。
线程安全
原因:多个线程访问出现延迟
线程随机性。
解决方案:同步
同步
同步前提:两个或者两个以上的线程
多个线程使用的是同一个锁
同步弊端:线程多时,对于同步上锁的判断会消耗很多的哦资源,降低运行效率
同步格式:
Synchronized(对象){
同步代码
}
同步的关键,控制共享的部分,即锁。
同步的锁:
同步代码的锁是object
同步函数的锁是this。因为函数的调用者是对象。
静态的同步函数的锁是类的字节码文件。因为静态函数在方法区中,是随着类的加载而加载的。
关于同步的思考思路总结:
明确哪些代码是多线程运行代码。
明确共享数据。
明确多线程运行代码中哪些语句是操作共享数据的。
死锁
即两个线程,各自持有各自的资源互不相让。因为只有获取了所需的资源和CPU才能执行程序。参考代码
class Ticket implements Runnable { private int tick = 1000; Object obj = new Object(); boolean flag = true; public void run() { if(flag) { while(true) { synchronized(obj) { show(); } } } else while(true) show(); } public synchronized void show()//this { synchronized(obj) { if(tick>0) { try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"....code : "+ tick--); } } } } class DeadLock { public static void main(String[] args) { Ticket t = new Ticket(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t1.start(); try{Thread.sleep(10);//让main线程沉睡一会 }catch(Exception e){} t.flag = false; t2.start(); } }
Condition和Lock
接口Condition:
Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。Condition 实例实质上被绑定到一个锁上。要为特定 Lock 实例获得 Condition 实例,请使用其 newCondition() 方法。
常用方法:
void await() 造成当前线程在接到信号或被中断之前一直处于等待状态。
void signal() 唤醒一个等待线程。
void signalAll() 唤醒所有等待线程。
类 ReentrantLock
一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。ReentrantLock 将由最近成功获得锁,并且还没有释放该锁的线程所拥有。当锁没有被另一个线程所拥有时,调用 lock 的线程将成功获取该锁并返回。如果当前线程已经拥有该锁,此方法将立即返回。可以使用 isHeldByCurrentThread() 和 getHoldCount() 方法来检查此情况是否发生。
此类的构造方法接受一个可选的公平 参数。当设置为 true 时,在多个线程的争用下,这些锁倾向于将访问权授予等待时间最长的线程。否则此锁将无法保证任何特定访问顺序。与采用默认设置(使用不公平锁)相比,使用公平锁的程序在许多线程访问时表现为很低的总体吞吐量(即速度很慢,常常极其慢),但是在获得锁和保证锁分配的均衡性时差异较小。不过要注意的是,公平锁不能保证线程调度的公平性。因此,使用公平锁的众多线程中的一员可能获得多倍的成功机会,这种情况发生在其他活动线程没有被处理并且目前并未持有锁时。还要注意的是,未定时的
tryLock 方法并没有使用公平设置。因为即使其他线程正在等待,只要该锁是可用的,此方法就可以获得成功。
获取锁的方法是: void lock()
获取condition实例方法: Condition newCondition()。
使用lock机制的参考代码:
/*作为一个示例,假定有一个绑定的缓冲区,它支持 put 和 take 方法。如果试图在空的缓冲区上执行 take 操作,则在某一个项变得可用之前,线程将一直阻塞;如果试图在满的缓冲区上执行 put 操作,则在有空间变得可用之前,线程将一直阻塞。我们喜欢在单独的等待 set 中保存 put 线程和 take 线程,这样就可以在缓冲区中的项或空间变得可用时利用最佳规划,一次只通知一个线程。可以使用两个 Condition 实例来做到这一点。*/ class BoundedBuffer { final Lock lock = new ReentrantLock(); final Condition notFull = lock.newCondition(); final Condition notEmpty = lock.newCondition(); final Object[] items = new Object[100]; int putptr, takeptr, count; public void put(Object x) throws InterruptedException { lock.lock(); try { while (count == items.length) notFull.await(); items[putptr] = x; if (++putptr == items.length) putptr = 0; ++count; notEmpty.signal(); } finally { lock.unlock(); } } public Object take() throws InterruptedException { lock.lock(); try { while (count == 0) notEmpty.await(); Object x = items[takeptr]; if (++takeptr == items.length) takeptr = 0; --count; notFull.signal(); return x; } finally { lock.unlock(); } } }
单例模式
参考代码*/ //饿汉式 class Single { private static final Single s = new Single(); private Single(){} public static Single getInstance() { return s; } } //懒汉式 class Single { private static Single s = null; private Single(){} public static Single getInstance() { if(s==null)//如果在对象为空的情况下,还去判断锁会很浪费资源,故进行两次判断。 { synchronized(Single.class) { if(s==null) //--->A; s = new Single(); } } return s; } }
相关文章推荐
- 黑马程序员——java语言基础部分——编码解码
- 黑马程序员——java语言基础部分——String、StringBuffer StringBuild学习笔记二
- 黑马程序员--java基础--语言基础部分
- 黑马程序员——java语言基础部分——String、StringBuffer StringBuild学习笔记一
- 黑马程序员——Java语言基础——04.多线程(2)线程间通信
- 黑马程序员_java语言的基础部分
- 黑马程序员_01_Java语言基础部分(数据类型与表达式、流程控制语句、数组与方法)
- 黑马程序员——java语言基础部分——学习盲点总结
- java编程基础2(java语言组成部分、常量和变量、比较运算符、)
- 黑马程序员——Java基础—线程
- C#语言 第五部分 线程(一)线程基础(1)
- 黑马程序员——JAVA基础------进程和线程
- 黑马程序员_java基础二(线程和集合)
- 黑马程序员——Java语言基础(二)---程序流程控制语句、函数
- 黑马程序员————Java基础语法部分之数组
- 黑马程序员————Java基础部分之面向对象(一)
- 黑马程序员-Java语言基础–面向对象 第10天
- 黑马程序员——java语言基础——组合,关联,聚合的区别
- 黑马程序员——java语言基础——总结一下学习过的类