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

来源:互联网 发布:it培训机构知乎 编辑:程序博客网 时间:2024/05/21 17:35

 

                            ------<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;}@Overridepublic 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).懒汉式

 

0 0
原创粉丝点击