您的位置:首页 > 职场人生

黑马程序员———多线程和死锁问题总结

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).懒汉式

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: