黑马程序员 Java多线程总结
2013-02-20 15:48
489 查看
------- android培训、java培训、java学习型技术博客、期待与您交流! ----------
什么是线程
进程:是一个正在执行的程序 (例如:windows任务管理器里面显示的那些就是进程)
线程:就是进程中的一个独立的控制单元,线程在控制着进程的执行,Java 虚拟机允许应用程序并发地运行多个执行线程。
多线程在JVM中的体现。
主线程:负责java程序的执行,该线程运行的代码存在于main方法中
还有负责垃圾回收机制的线程
如何自定义线程
继承Thread类
步骤
1,定义类继承Thread
2,复写Thread类中的run方法,将线程要运行的代码存放在该run方法中
3,创建类的对象,调用start方法,就是在启动线程,调用run方法
实现Runnable接口
步骤
1,定义类实现Runnable接口
2,覆盖Runnable接口中的run方法,将线程要运行的代码存放在该run方法中
3,通过Thread类建立线程对象
4,将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
5,调用Thread类的start方法开启线程并调用Runnable接口子类的run方法
两种方法的区别
实现Runnable接口的方法,避免了单继承的局限性
在定义线程时,建议使用实现方式
什么时候使用多线程
当某些代码需要同时被执行时就使用多线程
可以将这些代码分别封装成类形成多个线程
在实际开发中经常将多线程代码简写成匿名内部类的形式
线程的5种状态
被创建:
不具有执行资格,不具有执行权
运行:
具有执行资格,不具有执行权
冻结:
放弃执行资格,放弃执行权
临时阻塞:
具有执行资格,不具有执行权
消亡:
不具有执行资格,不具备执行权,线程消亡
多线程的安全问题
产生的原因:
多个线程操作共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行。导致共享数据的错误。
如何解决:
多个线程操作共享数据时,一个线程正在执行时,不让其他线程参与进来。
Java提供了专业的解决方式,就是同步代码块。
代码示例:卖票小程序
如何找问题
1,明确哪些代码是多线程运行代码。
2,明确共享数据。
3,明确多线程运行代码中哪些语句是操作共享数据的
同步代码块(同步函数)
如何使用:
synchronized(对象){
需要被同步的代码
}
同步的前提:
必须要有两个或者两个以上的线程;必须是多个线程使用同一个锁
利与弊:
解决了多线程的安全问题但是多个线程需要判断锁,较为消耗资源
关于锁:
同步代码块(任意锁)同步函数(this锁)静态同步函数(Class对象)
单例中懒汉式的安全问题
使用同步、双if判断,锁是本类对象的字节码文件(Single.class)
什么是死锁:
同步中嵌套同步,多个线程互相等待对方释放锁
线程间通信
多个线程,动作不同,操作同一资源
等待唤醒机制,使用了Object监视器方法,wait() notify() notifyAll()
这些方法只能使用在同步中,因为要对持有监视器(锁)的线程进行操作
生产者消费者问题:使用while判断标记,使用notifyAll唤醒对方
示例代码:
JDK1.5提供了一些新的对象,优化了等待唤醒机制。
1,将synchronized 替换成了Lock接口。
将隐式锁,升级成了显示锁。
Lock
获取锁:lock();
释放锁:unlock();注意:释放的动作一定要执行,所以通常定义在finally中。
获取Condition对象:newCondition();
2,将Object中的wait,notify,notifyAll方法都替换成了Condition的await,signal,signalAll。
和以前不同是:一个同步代码块具备一个锁,该所以具备自己的独立wait和notify方法。
现在是将wait,notify等方法,封装进一个特有的对象Condition,而一个Lock锁上可以有多个Condition对象。
如何停止线程
原理:
因为stop方法已经过时,现在只有让run方法结束才能停止线程,
开启多线程,运行代码通常是循环结构,控制住循环就可以让run方法结束。
如何实现:
可以通过让循环判断标记(boolean flag)的方式结束run方法,从而停止进程。
特殊情况:
当线程处于了冻结状态,就不会读取到标记,那么线程就不会结束。
interrupt:
可以清除线程的冻结状态,抛出InterruptedException异常
为了防止恢复后的线程继续进入循环,可以在处理异常时改变标记,结束循环。
Thread类方法总结
String getName() ;
返回该线程的名称。
static Thread currentThread() ;
返回对当前正在执行的线程对象的引用。
void interrupt() ;
清除线程的中断状态。
void join() ;
等待该线程终止。
当A线程执行到了B线程的join方法时,A就会等待,不管哪个线程抢到执行权,反正等B线程都执行完了,A才会执行。
void setDaemon(boolean on) ;
将该线程标记为守护线程或用户线程。
on如果为true,则将该线程标记为守护线程,当正在运行的线程都是守护线程时,Java 虚拟机退出。
该方法必须在启动线程前调用。
void setPriority(int newPriority);
更改线程的优先级。
参数应尽量使用静态常量
MAX_PRIORITY,MIN_PRIORITY,NORM_PRIORITY
static void yield() ;
暂停当前正在执行的线程对象,并执行其他线程。
临时释放执行权,减缓线程连续执行的频率,能使线程达到类似于平均运行的效果。
------- android培训、java培训、java学习型技术博客、期待与您交流! ----------
什么是线程
进程:是一个正在执行的程序 (例如:windows任务管理器里面显示的那些就是进程)
线程:就是进程中的一个独立的控制单元,线程在控制着进程的执行,Java 虚拟机允许应用程序并发地运行多个执行线程。
多线程在JVM中的体现。
主线程:负责java程序的执行,该线程运行的代码存在于main方法中
还有负责垃圾回收机制的线程
如何自定义线程
继承Thread类
步骤
1,定义类继承Thread
2,复写Thread类中的run方法,将线程要运行的代码存放在该run方法中
3,创建类的对象,调用start方法,就是在启动线程,调用run方法
class MyThread extends Thread { public void run() { // 这里写上线程的内容 } public static void main(String[] args) { new MyThread().start(); //使用这个方法启动一个线程 } }
实现Runnable接口
步骤
1,定义类实现Runnable接口
2,覆盖Runnable接口中的run方法,将线程要运行的代码存放在该run方法中
3,通过Thread类建立线程对象
4,将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
5,调用Thread类的start方法开启线程并调用Runnable接口子类的run方法
class MyThread implements Runnable { public void run() { // 这里写上线程的内容 } public static void main(String[] args) { new Thread(new MyThread()).start();// 使用这个方法启动一个线程 } }
两种方法的区别
实现Runnable接口的方法,避免了单继承的局限性
在定义线程时,建议使用实现方式
什么时候使用多线程
当某些代码需要同时被执行时就使用多线程
可以将这些代码分别封装成类形成多个线程
在实际开发中经常将多线程代码简写成匿名内部类的形式
new Thread() { public void run() { // 这里写上线程的内容 } }.start(); Runnable r = new Runnable() { public void run() { // 这里写上线程的内容 } }; new Thread(r).start();
线程的5种状态
被创建:
不具有执行资格,不具有执行权
运行:
具有执行资格,不具有执行权
冻结:
放弃执行资格,放弃执行权
临时阻塞:
具有执行资格,不具有执行权
消亡:
不具有执行资格,不具备执行权,线程消亡
多线程的安全问题
产生的原因:
多个线程操作共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行。导致共享数据的错误。
如何解决:
多个线程操作共享数据时,一个线程正在执行时,不让其他线程参与进来。
Java提供了专业的解决方式,就是同步代码块。
代码示例:卖票小程序
class Ticket implements Runnable { private int tick = 1000; Object obj = new Object(); public void run() { while(true) { synchronized(obj) { if(tick>0) { //try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--); } } } } } class TicketDemo2 { public static void main(String[] args) { Ticket t = new Ticket(); new Thread(t).start(); new Thread(t).start(); new Thread(t).start(); new Thread(t).start(); } }
如何找问题
1,明确哪些代码是多线程运行代码。
2,明确共享数据。
3,明确多线程运行代码中哪些语句是操作共享数据的
同步代码块(同步函数)
如何使用:
synchronized(对象){
需要被同步的代码
}
同步的前提:
必须要有两个或者两个以上的线程;必须是多个线程使用同一个锁
利与弊:
解决了多线程的安全问题但是多个线程需要判断锁,较为消耗资源
关于锁:
同步代码块(任意锁)同步函数(this锁)静态同步函数(Class对象)
单例中懒汉式的安全问题
使用同步、双if判断,锁是本类对象的字节码文件(Single.class)
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; } }
什么是死锁:
同步中嵌套同步,多个线程互相等待对方释放锁
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 DeadLockDemo { 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);}catch(Exception e){} t.flag = false; t2.start(); } }
线程间通信
多个线程,动作不同,操作同一资源
等待唤醒机制,使用了Object监视器方法,wait() notify() notifyAll()
这些方法只能使用在同步中,因为要对持有监视器(锁)的线程进行操作
生产者消费者问题:使用while判断标记,使用notifyAll唤醒对方
示例代码:
class ProducerConsumerDemo { public static void main(String[] args) { Resource r = new Resource(); Producer pro = new Producer(r); 4000 Consumer con = new Consumer(r); Thread t1 = new Thread(pro); Thread t2 = new Thread(pro); Thread t3 = new Thread(con); Thread t4 = new Thread(con); t1.start(); t2.start(); t3.start(); t4.start(); } } /* 对于多个生产者和消费者。 为什么要定义while判断标记。 原因:让被唤醒的线程再一次判断标记。 为什么定义notifyAll, 因为需要唤醒对方线程。 因为只用notify,容易出现只唤醒本方线程的情况。导致程序中的所有线程都等待。 */ class Resource { private String name; private int count = 1; private boolean flag = false; // t1 t2 public synchronized void set(String name) { while(flag) try{this.wait();}catch(Exception e){}//t1(放弃资格) t2(获取资格) this.name = name+"--"+count++; System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name); flag = true; this.notifyAll(); } // t3 t4 public synchronized void out() { while(!flag) try{wait();}catch(Exception e){}//t3(放弃资格) t4(放弃资格) System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name); flag = false; this.notifyAll(); } } class Producer implements Runnable { private Resource res; Producer(Resource res) { this.res = res; } public void run() { while(true) { res.set("+商品+"); } } } class Consumer implements Runnable { private Resource res; Consumer(Resource res) { this.res = res; } public void run() { while(true) { res.out(); } } }
JDK1.5提供了一些新的对象,优化了等待唤醒机制。
1,将synchronized 替换成了Lock接口。
将隐式锁,升级成了显示锁。
Lock
获取锁:lock();
释放锁:unlock();注意:释放的动作一定要执行,所以通常定义在finally中。
获取Condition对象:newCondition();
2,将Object中的wait,notify,notifyAll方法都替换成了Condition的await,signal,signalAll。
和以前不同是:一个同步代码块具备一个锁,该所以具备自己的独立wait和notify方法。
现在是将wait,notify等方法,封装进一个特有的对象Condition,而一个Lock锁上可以有多个Condition对象。
class Res { Lock lock = new ReentrantLock(); Condition con1 = lock.newCondition(); Condition con2 = lock.newCondition(); } public void set(...) throws InterruptedException { lock.lock(); try { con1.await(); ..... con2.signal(); } finally { lock.unlock();//释放锁的动作一定要执行 } }
如何停止线程
原理:
因为stop方法已经过时,现在只有让run方法结束才能停止线程,
开启多线程,运行代码通常是循环结构,控制住循环就可以让run方法结束。
如何实现:
可以通过让循环判断标记(boolean flag)的方式结束run方法,从而停止进程。
特殊情况:
当线程处于了冻结状态,就不会读取到标记,那么线程就不会结束。
interrupt:
可以清除线程的冻结状态,抛出InterruptedException异常
为了防止恢复后的线程继续进入循环,可以在处理异常时改变标记,结束循环。
Thread类方法总结
String getName() ;
返回该线程的名称。
static Thread currentThread() ;
返回对当前正在执行的线程对象的引用。
void interrupt() ;
清除线程的中断状态。
void join() ;
等待该线程终止。
当A线程执行到了B线程的join方法时,A就会等待,不管哪个线程抢到执行权,反正等B线程都执行完了,A才会执行。
void setDaemon(boolean on) ;
将该线程标记为守护线程或用户线程。
on如果为true,则将该线程标记为守护线程,当正在运行的线程都是守护线程时,Java 虚拟机退出。
该方法必须在启动线程前调用。
void setPriority(int newPriority);
更改线程的优先级。
参数应尽量使用静态常量
MAX_PRIORITY,MIN_PRIORITY,NORM_PRIORITY
static void yield() ;
暂停当前正在执行的线程对象,并执行其他线程。
临时释放执行权,减缓线程连续执行的频率,能使线程达到类似于平均运行的效果。
------- android培训、java培训、java学习型技术博客、期待与您交流! ----------
相关文章推荐
- 黑马程序员---java多线程学习总结
- 黑马程序员_java多线程的一些总结(二)
- 黑马程序员_03Java多线程知识总结
- 黑马程序员——java复习总结——多线程
- 黑马程序员_Java_多线程总结
- 黑马程序员—java之多线程总结
- 黑马程序员---------java多线程总结
- 黑马程序员-Java基础-多线程总结
- 黑马程序员_java的多线程(对第十一课创建多线程及多线程安全问题总结)
- 黑马程序员--多线程总结2--java
- 黑马程序员_java_多线程总结(下)
- 黑马程序员 知识点总结-Java多线程
- 黑马程序员-Java基础总结07——多线程
- 黑马程序员---------Java基础------------多线程简单总结
- 黑马程序员---Java基础总结--多线程
- 黑马程序员java学习笔记之四(java多线程总结)
- 黑马程序员:Java基础总结----多线程
- 黑马程序员 java多线程总结
- 黑马程序员_java多线程总结
- 黑马程序员:Java基础总结----多线程安全性&同步