黑马程序员———多线程和死锁问题总结
2015-08-14 21:44
344 查看
------<a target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
一.实现线程的两种方式:
方式一:
1.继承自Thread;
2.重写run();
3.启动:
1).实例化自定义线程的对象;
2).调用start();
class MyThread extends Thread{
public void run(){
//代码
}
}
main(){
MyThread t = new MyThread();
t.start();
}
方法二:
1.实现Runnable接口
2.重写run()方法;
3.启动:
1).实例化自定义对象;
2).实例化Thread对象,传递我们的自定义对象;
3).调用Thread的start()方法;
class MyRunnable implements Runnable{
public void run(){
//代码
}
}
main(){
MyRunnable myRun = new MyRunnable();
Thread t = new Thread(myRun);
t.start();
//写成一句话
new Thread(new MyRunnable()).start();
}
二.线程的调度:
1.休眠:sleep(long millis):
2.加入:join():调用join()的线程会保证先执行完毕,后续start()的线程会等待当前线程完成再执行;
3.礼让:yield():使当前线程退回到"就绪"状态,同其它线程站在同一起跑线上等待操作系统分配资源。
很有可能会被再次的分配到执行时间;
4.守护线程:setDaemon(true):守护线程:当主进程结束,守护线程同时结束。(不会立即,会有个小缓冲)
非守护线程:当主进程结束,非守护线程会继续执行。应用程序不会立即结束,会等待线程执行完毕;
5.中断:stop():过时:
interrupt():当线程内,处于Object--wait()或者Thread--join()或者Thread--sleep()三种阻塞状态时,会促使这种阻塞
发生异常,我们在异常处理的代码中可以结束掉当前的线程执行;
6.线程的生命周期:
新建--(start())-->就绪--(由操作系统分配)-->运行--(stop()或者interrupt()或者run()方法执行完毕)-->死亡
面试题:
1.当调用线程的start()方法后,线程就会立即运行;这句话说得不对。
三.同步:
1.当多个线程访问同一资源时,会产生"并发访问"的问题:
2."并发性访问"的判断标准:
1).是否是多线程环境
2).是否有共享数据
3).是否有多条语句操作共享数据
3.解决方法:加锁:使用关键字:synchronized
4.语法格式:
1).同步代码块:
synchronized(被锁的对象){
}
2).同步方法:
public synchronized void set(int num){
}
3.静态方法内部也可以定义同步代码块;
public static void show(){
synchronized(class对象){
}
}
4).静态方法也可以被声明为synchronized:
public synchronized static void show(){
}
例子:
<span style="font-family:KaiTi_GB2312;font-size:14px;">package cn.itcast.demo15_模拟银行账户_同步代码块和同步方法; public class Demo { public static void main(String[] args) { //1.实例化账户 Accound acc = new Accound(); //2.两个线程 SetThread setT = new SetThread(acc); GetThread getT = new GetThread(acc); //3.启动两个线程 setT.start(); getT.start(); //主进程为了打印最后的余额,等待1秒,保证两个线程先完成 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //打印余额 System.out.println("最终余额:" + acc.getBalance()); } } </span>
<span style="font-family:KaiTi_GB2312;font-size:14px;">package cn.itcast.demo15_模拟银行账户_同步代码块和同步方法; public class Accound { private int balance = 1000000; /* public void set(int num){ //同步代码块 synchronized (this) { //存钱 this.balance += num; } } public void get(int num){//取钱的线程 //同步代码块 synchronized (this) { this.balance -= num; } } */ //同步方法:锁的对象:当前对象,相当于 synchronized(this) public synchronized void set(int num){ this.balance += num; } public synchronized void get(int num){//取钱的线程 this.balance -= num; } //静态方法:内部可不可以包含synchronized代码块?OK的 public static void show(){ //一般静态方法中的同步代码块,不能锁:this对象。一般锁:这个类的class对象; synchronized (Accound.class) { System.out.println("show()"); } } //静态方法:可不可以是synchronized的方法?OK的; public synchronized static void show2(){ System.out.println("show2()"); } public int getBalance(){ return this.balance; } } </span>
<span style="font-family:KaiTi_GB2312;font-size:14px;">package cn.itcast.demo15_模拟银行账户_同步代码块和同步方法; public class GetThread extends Thread { private Accound accound; public GetThread(Accound acc){ this.accound = acc; } @Override public void run() { for(int i = 0;i < 1000 ; i++){ this.accound.get(1000); } System.out.println("取钱完毕!"); } }</span>
<span style="font-family:KaiTi_GB2312;font-size:14px;">package cn.itcast.demo15_模拟银行账户_同步代码块和同步方法; public class SetThread extends Thread { private Accound accound; public SetThread(Accound acc){ this.accound = acc; } public void run() { for(int i = 0 ;i < 1000 ;i ++){ this.accound.set(1000); } System.out.println("存钱完毕!"); }; } </span>
一.JDK5的Lock锁:
Lock o = .....;
o.lock();
try{
}finally{
o.unlock();
}
二.死锁问题:
1.基于同步锁,当锁定某对象时,其它对象会对此对象进行访问,在不释放锁的情况下,其它线程会一直等待;
如果双方线程都在如此等待时,这就是:死锁;
2.死锁问题的解决:见:"什么是死锁及死锁的必要条件和解决方法.doc"
三.生产消费者问题:
1.一方生产,一方消费:此例只适用于"单生产"和"单消费"的情况;
2.解决:
在共享资源内部,当资源没有准备好时,可以让当前访问的线程等待:Object-->wait();
在准备好资源后,可以唤醒等待的线程:notify():唤醒一个线程;
notifyAll():唤醒所有等待的线程;
四.线程组:
1.线程都有线程组,默认线程组:main;
2.设定线程组:
1).实例化我们的线程类;
2).实例化线程组;
3).实例化一个Thread,传递参数:线程组对象、线程对象、线程名称
MyThread myT1 = new MyThread();
ThreadGroup group = new ThreadGroup("我的线程组");
Thread t = new Thread(group,myT1,"线程1");
3.线程组的意义:
可以对多个线程进行统一管理,可以统一执行操作;例如:一次性停止线程组内的所有线程;
五.线程池:
1.JDK5之后;
2.实现方式:
1).获取线程池:
ExecutorService service = Executors.newFixedThreadPool(2);
//调用service的submit()方法
MyThread t1 = new MyThread();
Future<?> result = service.submit(t1);
//获取返回值:
Object value = result.get();
2).可以反复的运行线程池中的线程对象
service.submit(t1);
六.JDK5的线程实现方式:
1.实现Callable接口
2.重写call()方法;
3.启动:
使用线程池的方式;
特点:JDK5的线程方式可以获取返回值,并且call方法可以抛出异常;
七.定时器
1.TimerTask(抽象类):定义任务:
1).自定义类,继承自TimerTask;
2).重写run()方法;
2.Timer(类):启动定时器,执行任务;
1).实例化一个Timer();
2).public void schedule(TimerTask task, long delay):在指定的时间执行指定的任务。只执行一次。
public void schedule(TimerTask task,long delay,long period):在指定的时间,执行任务,并每隔period时间,反复的执行;
八.设计模式:
1.简单工厂模式:
2.工厂方法模式:
3.单例模式:
1).饿汉式
2).懒汉式
相关文章推荐
- ios面试基础
- 网易校招面试
- 黑马程序员 多线程
- 阿里巴巴面试题集合(转)
- 黑马程序员-Java高级:多线程
- 黑马程序员一一Java的多线程笔记
- 黑马程序员--面向对象
- 【转】Java线程面试题Top50
- 黑马程序员--IO,递归总结,
- 黑马程序员-Scanner的使用、string类的概述和使用
- 黑马程序员-多态的讲解
- 10个iOS面试问题,面试者轻松自如
- 黑马程序员——java复习总结——File类和其他流对象
- [.Net码农]C# 工程中引用出现感叹号
- 黑马程序员 多态,抽象类与接口
- [.Net码农]NPOI读写Excel
- 程序员跳槽全攻略
- 黑马程序员 继承
- 程序员的数学思维修炼
- 给程序员的七个建议