2017年4月14号 星期五 空气质量:重度污染
内容:多线程第一节课
一、进程、线程和多线程
老师代码:
package cn.bdqn.util;
public class ReadeMe {
/**
*
* 进程:由一个或者多个线程组成!
* 应用程序(QQ,微信)的执行实例!有自己独立的内存空间和系统资源!
*
* 线程: cpu真正执行的是 线程!是cpu调度和分配的最基本的单位!
*
* 我们感觉是同一个时间点,cpu在运行多个程序!----》多线程!
* 因为cpu在一个时间点,只能执行一个线程!
* 多线程交替占用cpu的资源!并不是真正的同时执行多个线程!
*
* 例子:
* 01. 现在地铁有5个进站口! 有5个人 可以 同时(看着像同时)进站!
* 02. 现在地铁有1个进站口! 有5个人 必须 排队 进站!
* 问题?
* 哪个效率高? 01效率高!
*
* 地铁 : CPU
* 进站口:线程
*
* 多线程的好处:
* 01.充分利用cpu的资源
* 02.给用户带来良好的体验
*
*
*/
package cn.bdqn.thread;
public class MyThread {
public static void main(String[] args) {
// 获取当前执行的线程
Thread t = Thread.currentThread();
System.out.println(t);
/**
* t的输出:Thread[main,5,main]
* 01.按理说应该输出的是 全类名+@+hash
* 02.但是输出的是Thread[main,5,main]
* 03.可以断定 Thread重写了 Object类中的toString()
* main:主线程的名称
* 5:当前线程的优先级 默认是5,最小是1,最大是10
* main:所属线程组的名称
*/
// 更改当前线程的名称
t.setName("主线程");
System.out.println("当前线程的名称是:" + t.getName());
System.out.println(t);
}
}
}
二、实现多线程的两种方式之一(继承Thread类)及start和run的区别
老师代码:
package cn.bdqn.thread01;
/**
* 实现多线程 的方式:
* 01.类 继承Thread类,并且重写Thread中的run()方法!
*/
public class MyThread extends Thread {
// 重写Thread中的run()方法! 是普通的方法!
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
// 输出当前线程的名称 +i
System.out.println(Thread.currentThread().getName() + "====>" + i);
}
}
// 主线程
public static void main(String[] args) {
/** 实例化线程类
* 01.创建了2个线程类对象
* 02.分别执行run()
* 03.run()本身就是一个普通的方法,并不是代表启动线程!
* 04.thread1.run() 这时候对象1 先执行run() 执行完毕 再执行对象2的run()
* MyThread thread1 = new MyThread();
* MyThread thread2 = new MyThread();
* thread1.run();
* thread2.run();
*/
MyThread thread1 = new MyThread();
MyThread thread2 = new MyThread();
thread1.setName("线程111");
thread2.setName("线程222");
thread1.start(); // 电脑上双击QQ
thread2.start(); // 电脑上双击微信
/**
* 01.创建了2个线程类对象
* 02.分别执行start(),代表线程开启
* 03.线程开启,就代表两个线程会交替执行!
* 问题:
* thread1.start(); 能保证对象1就先执行吗? 不能!
*/
}
/**
* start 和 run 的区别!
*
* run:普通的方法!也成为线程体!cpu分配时间片给当前线程的时候,线程才会真正的执行!
*
* start:我们所写的线程类中并没有start(),但是父类中有!继承父类的方法!
* 启动线程!不是线程的执行,在调用start方法的时候,底层默认会执行run()!
*
*
}
三、实现多线程的两种方式之二(实现Runnable接口)
老师代码:
package cn.bdqn.runnable02;
/**
* 02.实现 Runnable接口 重写 run()
*
*/
public class MyThread implements Runnable {
// 重写Thread中的run()方法! 是普通的方法!
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
// 输出当前线程的名称 +i
System.out.println(Thread.currentThread().getName() + "====>" + i);
}
}
// main 主线程
public static void main(String[] args) {
// 创建线程对象
MyThread thread = new MyThread();
// 发现没有 Start()
Thread thread1 = new Thread(thread);
Thread thread2 = new Thread(thread);
// 开启线程
thread1.start();
thread2.start();
}
}
四、线程的生命周期(附带图示)
老师代码:
* 线程的生命周期!
*
* 01.新生状态
* MyThread thread1 = new MyThread();
* 02.就绪状态
* thread1.start();
* 03.运行状态
* cpu分配时间片给thread1的时候,开始执行run()
* 04.阻塞状态
* sleep(),wait(),join(),yield();
* 05.死亡状态
* 01.正常死亡 run()执行完毕
* 02.异常死亡 run()执行过程中,出现异常退出的情况!
*
*/
五、线程的阻塞状态(interrupted)
老师代码:
package cn.bdqn.interrupted03;
/**
*
线程的阻塞状态
01.InterruptedException(见第六部分)
02.sleep 和 wait 的区别(见第七部分)
001.sleep 在 Thread类中,wait 在Object类中
002.sleep休眠,占用cpu资源,不释放锁!后续线程等待! 使用interrupted()唤醒
003.wait 等待! 不占用cpu资源!使用notify()唤醒
*
*/
public class MyThread implements Runnable {
// 重写Thread中的run()方法! 是普通的方法!
@Override
public void run() {
try {
System.out.println("线程的运行状态");
System.out.println("线程的阻塞状态");
Thread.sleep(3000);
for (int i = 1; i <= 10; i++) {
System.out.println(Thread.currentThread().getName() + "====>"
+ i);
}
} catch (InterruptedException e) {
System.out.println("线程异常死亡");
}
System.out.println("线程正常死亡");
}
public static void main(String[] args) {
MyThread thread = new MyThread();
Thread thread1 = new Thread(thread);
System.out.println("线程的新生状态");
thread1.start();
System.out.println("线程的就绪状态");
}
}
六、InterruptedException相关知识
转载:http://blog.csdn.net/derekjiang/article/details/4845757
当一个方法后面声明可能会抛出InterruptedException 异常时,说明该方法是可能会花一点时间,但是可以取消的方法。
抛InterruptedException的代表方法有:
1. Java.lang.Object 类的 wait 方法
2. java.lang.Thread 类的 sleep 方法
3. java.lang.Thread 类的 join 方法
-- 需要花点时间的方法
执行wait方法的线程,会进入等待区等待被notify/notify All。在等待期间,线程不会活动。
执行sleep方法的线程,会暂停执行参数内所设置的时间。
执行join方法的线程,会等待到指定的线程结束为止。
因此,上面的方法都是需要花点时间的方法。
-- 可以取消的方法
因为需要花时间的操作会降低程序的响应性,所以可能会取消/中途放弃执行这个方法。
这里主要是通过interrupt方法来取消。
1. sleep方法与interrupt方法
interrupt方法是Thread类的实例方法,在执行的时候并不需要获取Thread实例的锁定,任何线程在任何时刻,都可以通过线程实例来调用其他线程的interrupt方法。
当在sleep中的线程被调用interrupt方法时,就会放弃暂停的状态,并抛出InterruptedException异常,这样一来,线程的控制权就交给了捕捉这个异常的catch块了。
2. wait方法和interrupt方法
当线程调用wait方法后,线程在进入等待区时,会把锁定接触。当对wait中的线程调用interrupt方法时,会先重新获取锁定,再抛出InterruptedException异常,获取锁定之前,无法抛出InterruptedException异常。
3. join方法和interrupt方法
当线程以join方法等待其他线程结束时,一样可以使用interrupt方法取消。因为join方法不需要获取锁定,故而与sleep一样,会马上跳到catch程序块
-- interrupt方法干了什么?
interrupt方法其实只是改变了中断状态而已。
而sleep、wait和join这些方法的内部会不断的检查中断状态的值,从而自己抛出InterruptEdException。
所以,如果在线程进行其他处理时,调用了它的interrupt方法,线程也不会抛出InterruptedException的,只有当线程走到了sleep, wait, join这些方法的时候,才会抛出InterruptedException。若是没有调用sleep, wait, join这些方法,或者没有在线程里自己检查中断状态,自己抛出InterruptedException,那InterruptedException是不会抛出来的。
isInterrupted方法,可以用来检查中断状态
Thread.interrupted方法,可以用来检查并清除中断状态。
七、sleep 和 wait 的区别
转载:http://blog.csdn.net/liuzhenwen/article/details/4202967
第一种解释:
功能差不多,都用来进行线程控制,他们最大本质的区别是:sleep()不释放同步锁,wait()释放同步缩.
还有用法的上的不同是:sleep(milliseconds)可以用时间指定来使他自动醒过来,如果时间不到你只能调用interreput()来强行打断;wait()可以用notify()直接唤起.
第二种解释:
sleep是Thread类的静态方法。sleep的作用是让线程休眠制定的时间,在时间到达时恢复,也就是说sleep将在接到时间到达事件事恢复线程执行,例如:
try{
System.out.println("I'm going to bed");
Thread.sleep(1000);
System.out.println("I wake up");
}
catch(IntrruptedException e) {
}
wait是Object的方法,也就是说可以对任意一个对象调用wait方法,调用wait方法将会将调用者的线程挂起,直到其他线程调用同一个对象的notify方法才会重新激活调用者,例如:
//Thread 1
try{
obj.wait();//suspend thread until obj.notify() is called
}
catch(InterrputedException e) {
}
第三种解释:
这两者的施加者是有本质区别的.
sleep()是让某个线程暂停运行一段时间,其控制范围是由当前线程决定,也就是说,在线程里面决定.好比如说,我要做的事情是 "点火->烧水->煮面",而当我点完火之后我不立即烧水,我要休息一段时间再烧.对于运行的主动权是由我的流程来控制.
而wait(),首先,这是由某个确定的对象来调用的,将这个对象理解成一个传话的人,当这个人在某个线程里面说"暂停!",也是 thisOBJ.wait(),这里的暂停是阻塞,还是"点火->烧水->煮饭",thisOBJ就好比一个监督我的人站在我旁边,本来该线 程应该执行1后执行2,再执行3,而在2处被那个对象喊暂停,那么我就会一直等在这里而不执行3,但正个流程并没有结束,我一直想去煮饭,但还没被允许, 直到那个对象在某个地方说"通知暂停的线程启动!",也就是thisOBJ.notify()的时候,那么我就可以煮饭了,这个被暂停的线程就会从暂停处 继续执行.
其实两者都可以让线程暂停一段时间,但是本质的区别是一个线程的运行状态控制,一个是线程之间的通讯的问题
在Java.lang.Thread类中,提供了sleep(),
而java.lang.Object类中提供了wait(), notify()和notifyAll()方法来操作线程
sleep()可以将一个线程睡眠,参数可以指定一个时间。
而wait()可以将一个线程挂起,直到超时或者该线程被唤醒。
wait有两种形式wait()和wait(milliseconds).
sleep和wait的区别有:
1,这两个方法来自不同的类分别是Thread和Object
2,最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
3,wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在
任何地方使用
synchronized(x){
x.notify()
//或者wait()
}
4,sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常
![](https://images2015.cnblogs.com/blog/1104253/201704/1104253-20170414161016970-874693553.png)
package cn.bdqn.priority04;
/**
* 线程的调度:
* 按照我们指定的规则,给多个线程分配cpu的资源!
*
线程的优先级
从 1-10 默认是5
优先级越高代表 获得cpu资源的概率越大! 概率大并不能代表一定能获取资源!
有可能概率小的总是拿到资源!
*/
public class MyThread implements Runnable {
// 重写Thread中的run()方法! 是普通的方法!
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
System.out.println(Thread.currentThread().getName() + "====>" + i);
}
}
public static void main(String[] args) {
Thread thread1 = new Thread(new MyThread(), "线程1");
Thread thread2 = new Thread(new MyThread(), "线程2");
System.out.println("thread1默认的优先级:" + thread1.getPriority());
System.out.println("thread2默认的优先级:" + thread2.getPriority());
thread1.setPriority(Thread.MAX_PRIORITY); // 优先级最高
thread2.setPriority(Thread.MIN_PRIORITY); // 优先级最低
System.out.println("************************");
System.out.println("thread1修改后的优先级:" + thread1.getPriority());
System.out.println("thread2修改后的优先级:" + thread2.getPriority());
// 启动线程
thread1.start();
thread2.start();
}
}
package cn.bdqn.join05;
/**
* 线程的调度:
* 按照我们指定的规则,给多个线程分配cpu的资源!
*
* join:等待该线程执行完毕!
*/
public class MyThread implements Runnable {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + "====>" + i);
}
}
// 主线程main
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new MyThread(), "线程1");
thread1.start();
// 当前是2个线程
for (int j = 1; j <= 50; j++) {
if (j == 10) { // 当主线程中的i为10的时候,我让thread1强行执行
thread1.join(); // 主线程必须等待thread1执行完毕 才能继续执行
}
System.out.println(Thread.currentThread().getName() + "====>" + j);
}
}
}
package cn.bdqn.yield06;
/**
* 线程的调度:
* 按照我们指定的规则,给多个线程分配cpu的资源!
*
* yield: 线程之间的礼让,还是概率问题!
* 可能我让你了,你不接受!
*/
public class MyThread implements Runnable {
@Override
public void run() {
for (int i = 1; i <= 50; i++) {
System.out.println(Thread.currentThread().getName() + "====>" + i);
if (i % 2 == 0) {
System.out.println("线程礼让");
Thread.yield();
}
}
}
// 主线程main
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new MyThread(), "线程1");
Thread thread2 = new Thread(new MyThread(), "线程2");
thread1.start();
thread2.start();
}
}
![](https://images2015.cnblogs.com/blog/1104253/201704/1104253-20170414145026626-541908995.jpg)