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

 

                            ------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
一.实现线程的两种方式:
 方式一:
  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(){
   }

例子:

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());
		
		
	}
}


 

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;
	}
	
}


 

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("取钱完毕!");
	}
}


 

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("存钱完毕!");
	};
}


 

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

 

你可能感兴趣的:(黑马程序员———多线程和死锁问题总结)