黑马程序员—— 多线程

---------------------- ASP.Net+Android+IO开发S.Net培训、期待与您交流! ------------------------


多线程

1. 多线程:如果一个程序有多条执行路径,这就是一个多线程的程序。
    进程:正在执行的程序。 线程:程序的执行路径。执行单元。
    举例:360管理界面,迅雷下载。
    jvm的启动是多线程的因为它至少启动了main线程和垃圾回收线程。
2. 线程的四种状态

   

    被创建--start()-->运行--sleep()/wait()-->冻结---->消亡
    被创建--stop()-->消亡   冻结--notify()/notify()-->运行
    运行-->run()/stop()-->消亡
    sleep方法需要指定睡眠时间,单位是毫秒。
    一个特殊的状态:就绪。具备了执行资格,但是还没有获取资源。
3. 线程的创建
    创建线程方式一
    (1) 继承Thread类
    (2) 子类覆盖父类中的run方法,将线程运行的代码存放在run中。
    (3) 建立子类对象的同时线程也被创建。
    (4) 通过调用start方法开启线程。
    创建线程方式二
    (1) 实现Runnable接口
    (2) 子类覆盖接口中的run方法。
    (3) 通过Thread类创建线程,
        并将实现了Runnable接口的子类对象作为参数传递给Thread类的构造函数。
    (4) Thread类对象调用start方法开启线程。
    run()和start()的区别:
    run()里面封装的是线程执行的代码,如果直接调用,是普通方法调用。
    start()做了两件事情:启动了线程,调用了run()方法。
    要把自定义的类对象作为Thread类对象的构造参数传递的原因:
    因为自定义的类它没有start()方法,只有Thread类有。
    而如果单独创建Thread类的对象使用。那么,
    最终使用的run方法默认情况下跟自定义的类对象无关。
    为了让Thread类调用run()是自定义类里面的,所以,我们把它作为参数传递。
4. 线程安全问题
    导致安全问题的出现的原因:多个线程访问出现延迟。线程随机性。
    注:线程安全问题在理想状态下,不容易出现,
    但一旦出现对软件的影响是非常大的。
    判断一段程序有没有线程安全问题的依据:
        (1) 有没有共享数据
        (2) 有没有多条语句操作共享数据
        (3) 是否是被多个线程访问
    线程安全问题的解决
        (1) 同步代码块
        synchronized(对象) //锁对象:任意对象 { 需要被同步的代码; }
        (2) 同步方法
        在方法修饰用synchronized关键字。锁对象:this
        (3) 静态同步方法: 锁对象为当前类的Class文件对象。
5. 同步(synchronized)及特点
    格式:synchronized(对象){ 需要同步的代码;}
    同步可以解决安全问题的根本原因就在那个对象上。
    该对象如同锁的功能。
    同步的前提:同步需要两个或者两个以上的线程。多个线程使用的是同一个锁。
    未满足这两个条件,不能称其为同步。
    同步的弊端:当线程相当多时,因为每个线程都会去判断同步上的锁,
    这是很耗费资源的,无形中会降低程序的运行效率。
    同步方法: 格式,在函数上加上synchronized修饰符即可。
8. 线程间通信
    wait(),notify(),notifyAll(),用来操作线程定义在了Object类中的原因:
    (1) 这些方法存在与同步中。
    (2) 使用这些方法时必须要标识所属的同步的锁。
    (3) 锁可以是任意对象,所以任意对象调用的方法一定定义Object类中。
    (4) wait(),sleep()的区别:
        wait(): 释放cpu执行权,释放锁。
        sleep(): 释放cpu执行权,不释放锁。
9. 停止线程
    定义循环结束标记,因为线程运行代码一般都是循环,只要控制了循环即可。
    使用interrupt(中断)方法。该方法是结束线程的冻结状态,使线程回到运行状态中来。
    注:stop方法已经过时不再使用。
10. 线程类的其他方法
    currentThread():返回当前正在执行的线程对象    
    setPriority(int num): 更改线程的优先级。
    setDaemon(boolean b): 将该线程标记为守护线程或用户线程。
    join(): 等待该线程终止。
    toString(): 返回该线程的字符串表示形式,包括线程名称、优先级和线程组。
11. 单例设计模式
    保证类在内存中只有一个对象。饿汉式(开发用)与懒汉式(面试用)
    实现原理:
        (1) 让外界不能创建对象,私有化构造方法
        (2) 自己创建一个对象,私有并静态化自己创建的对象
        (3) 提供公共的访问方式,通过静态方法返回创建的静态成员对象.
    单例设计的应用: 网站的计数器,windows的打印服务。
    在JDK的源码中,有一个类也使用的是单例设计模式: Runtime

代码实例: 

// 学生类的单例(饿汉式)

  1. <SPAN style="FONT-SIZE: 14px">package cn.lzz.single;  
  2.   
  3. public class Student {  
  4.     private Student(){}  
  5.     private static  Student s = new Student();  
  6.     public static final Student getInstance(){  
  7.         return s;  
  8.     }  
  9.     private String name;  
  10.     private int Score;  
  11.     public String getName() {  
  12.         return name;  
  13.     }  
  14.     public void setName(String name) {  
  15.         this.name = name;  
  16.     }  
  17.     public int getScore() {  
  18.         return Score;  
  19.     }  
  20.     public void setScore(int score) {  
  21.         Score = score;  
  22.     }  
  23.     public void display(){  
  24.         System.out.println("姓名: "+getName()+"\t成绩: "+getScore());  
  25.     }  
  26. }  
  27. </SPAN>  
package cn.lzz.single;

public class Student {
	private Student(){}
	private static  Student s = new Student();
	public static final Student getInstance(){
		return s;
	}
	private String name;
	private int Score;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getScore() {
		return Score;
	}
	public void setScore(int score) {
		Score = score;
	}
	public void display(){
		System.out.println("姓名: "+getName()+"\t成绩: "+getScore());
	}
}

  1. <SPAN style="FONT-SIZE: 14px">// 老师类的单例(懒汉式)   
  2.   
  3. package cn.lzz.single;  
  4.   
  5. public class Teacher {  
  6.     private Teacher(){}  
  7.     private Teacher(String name){  
  8.         this.name = name;  
  9.     }  
  10.     private static Teacher t = null;  
  11.     public static synchronized Teacher getInstance(){  
  12.         if(t == null){  
  13.             t = new Teacher("LZZ");  
  14.         }  
  15.         return t;  
  16.     }  
  17.       
  18.     private String name;  
  19.     public String getName() {  
  20.         return name;  
  21.     }  
  22.     public void setName(String name) {  
  23.         this.name = name;  
  24.     }  
  25.     public void show(){  
  26.         System.out.println("姓名: "+getName());  
  27.     }  
  28. }  
  29. </SPAN>  
// 老师类的单例(懒汉式)

package cn.lzz.single;

public class Teacher {
    private Teacher(){}
    private Teacher(String name){
        this.name = name;
    }
    private static Teacher t = null;
    public static synchronized Teacher getInstance(){
        if(t == null){
            t = new Teacher("LZZ");
        }
        return t;
    }
    
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void show(){
        System.out.println("姓名: "+getName());
    }
}

// 单例测试

  1. <SPAN style="FONT-SIZE: 14px">package cn.lzz.single;  
  2.   
  3. public class SingleTest {  
  4.   
  5.     /** 
  6.      * @param args 
  7.      */  
  8.     public static void main(String[] args) {  
  9.         // TODO Auto-generated method stub   
  10. //      Student s = new Student();   
  11.         Student s = Student.getInstance();  
  12.         s.setName("张三");  
  13.         s.setScore(33);  
  14.         s.display();  
  15.           
  16.         Teacher t1 = Teacher.getInstance();   
  17.         Teacher t2 = Teacher.getInstance();  
  18.         t1.show();  
  19.         t2.show();  
  20.         System.out.println("t1==t2: "+(t1==t2));  
  21.     }  
  22.   
  23. }  
  24. </SPAN>  
package cn.lzz.single;

public class SingleTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
//		Student s = new Student();
		Student s = Student.getInstance();
		s.setName("张三");
		s.setScore(33);
		s.display();
		
		Teacher t1 = Teacher.getInstance();	
		Teacher t2 = Teacher.getInstance();
		t1.show();
		t2.show();
		System.out.println("t1==t2: "+(t1==t2));
	}

}

单例测试结果


练习巩固

1.  线程示例(继承Thread类)


  1. <SPAN style="FONT-SIZE: 14px">package cn.lzz.thread;  
  2.   
  3. public class ThreadDemo extends Thread {  
  4.     private String name;  
  5.     ThreadDemo(String name){  
  6.         super(name);  
  7.     }  
  8.     @Override  
  9.     public void run() {  
  10.         for (int i = 0; i < 50; i++) {             
  11.             System.out.println(Thread.currentThread().getName()+"..."+i);  
  12.         }  
  13.     }  
  14. }  
  15. </SPAN>  
package cn.lzz.thread;

public class ThreadDemo extends Thread {
	private String name;
	ThreadDemo(String name){
		super(name);
	}
	@Override
	public void run() {
		for (int i = 0; i < 50; i++) {			
			System.out.println(Thread.currentThread().getName()+"..."+i);
		}
	}
}

线程示例测试结果



2. 售票例子(实现Runnable接口)

  1. <SPAN style="FONT-SIZE: 14px">package cn.lzz.thread_app;  
  2.   
  3. import java.util.concurrent.locks.Lock;  
  4. import java.util.concurrent.locks.ReentrantLock;  
  5.   
  6. //class Demo{}   
  7.   
  8. public class TicketDemo implements Runnable {  
  9.     // 定义100张票   
  10.     private int tickets = 100;  
  11.   
  12.     // private Object obj = new Object();   
  13.     // Demo obj = new Demo();   
  14.   
  15.     private Lock lock = new ReentrantLock();  
  16.   
  17.     @Override  
  18.     public void run() {  
  19.         while (true) {  
  20.   
  21.             // synchronized(obj){   
  22.             lock.lock();  
  23.             if (tickets > 0) {  
  24.                 try {  
  25.                     Thread.sleep(10);  
  26.                 } catch (InterruptedException e) {  
  27.                     e.printStackTrace();  
  28.                 }  
  29.                 System.out.println(Thread.currentThread().getName() + "正在出售第"  
  30.                         + (tickets--) + "张票");  
  31.             }  
  32.             lock.unlock();  
  33.             // }   
  34.   
  35.         }  
  36.     }  
  37.   
  38. }  
  39. </SPAN>  
package cn.lzz.thread_app;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

//class Demo{}

public class TicketDemo implements Runnable {
	// 定义100张票
	private int tickets = 100;

	// private Object obj = new Object();
	// Demo obj = new Demo();

	private Lock lock = new ReentrantLock();

	@Override
	public void run() {
		while (true) {

			// synchronized(obj){
			lock.lock();
			if (tickets > 0) {
				try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + "正在出售第"
						+ (tickets--) + "张票");
			}
			lock.unlock();
			// }

		}
	}

}

// 售票例子测试

  1. <SPAN style="FONT-SIZE: 14px">package cn.lzz.thread_app;  
  2.   
  3. public class TicketDemoTest {  
  4.   
  5.     /** 
  6.      * @param args 
  7.      */  
  8.     public static void main(String[] args) {  
  9.         // 创建实现了Runnable接口的子类对象   
  10.         TicketDemo td = new TicketDemo();  
  11.   
  12.         // 创建线程对象   
  13.         Thread t1 = new Thread(td, "窗口1");  
  14.         Thread t2 = new Thread(td, "窗口2");  
  15.         Thread t3 = new Thread(td, "窗口3");  
  16.         Thread t4 = new Thread(td, "窗口4");  
  17.   
  18.         t1.start();  
  19.         t2.start();  
  20.         t3.start();  
  21.         t4.start();  
  22.   
  23.     }  
  24.   
  25. }  
  26. </SPAN>  
package cn.lzz.thread_app;

public class TicketDemoTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// 创建实现了Runnable接口的子类对象
		TicketDemo td = new TicketDemo();

		// 创建线程对象
		Thread t1 = new Thread(td, "窗口1");
		Thread t2 = new Thread(td, "窗口2");
		Thread t3 = new Thread(td, "窗口3");
		Thread t4 = new Thread(td, "窗口4");

		t1.start();
		t2.start();
		t3.start();
		t4.start();

	}

}

售票例子运行结果



3. 死锁示例


  1. package cn.lzz.thread;  
  2.   
  3. class Test implements Runnable{  
  4.     private boolean flag;  
  5.     Test(boolean flag){  
  6.         this.flag = flag;  
  7.     }  
  8.     public void run(){  
  9.         if(flag){  
  10.             synchronized(MyLock.locka){  
  11.                 System.out.println(Thread.currentThread().getName()+"...if...locka...");  
  12.                 synchronized(MyLock.lockb){  
  13.                     System.out.println(Thread.currentThread().getName()+"...if...lockb...");  
  14.                 }  
  15.             }  
  16.         }else{  
  17.             synchronized(MyLock.lockb){  
  18.                 System.out.println(Thread.currentThread().getName()+"...else...lockb...");  
  19.                 synchronized(MyLock.locka){  
  20.                     System.out.println(Thread.currentThread().getName()+"...else...locka...");  
  21.                 }  
  22.             }  
  23.         }  
  24.     }  
  25. }  
  26.   
  27. class MyLock{  
  28.     public static final Object locka = new Object();  
  29.     public static final Object lockb = new Object();  
  30. }  
  31.   
  32.   
  33. public class DeadLockTest {  
  34.   
  35.     /** 
  36.      * @param args 
  37.      */  
  38.     public static void main(String[] args) {  
  39.         // TODO Auto-generated method stub   
  40.         Test a = new Test(true);  
  41.         Test b = new Test(false);  
  42.         Thread t1 = new Thread(a);  
  43.         Thread t2 = new Thread(b);  
  44.         t1.start();  
  45.         t2.start();  
  46.     }  
  47.   
  48. }  
package cn.lzz.thread;

class Test implements Runnable{
	private boolean flag;
	Test(boolean flag){
		this.flag = flag;
	}
	public void run(){
		if(flag){
			synchronized(MyLock.locka){
				System.out.println(Thread.currentThread().getName()+"...if...locka...");
				synchronized(MyLock.lockb){
					System.out.println(Thread.currentThread().getName()+"...if...lockb...");
				}
			}
		}else{
			synchronized(MyLock.lockb){
				System.out.println(Thread.currentThread().getName()+"...else...lockb...");
				synchronized(MyLock.locka){
					System.out.println(Thread.currentThread().getName()+"...else...locka...");
				}
			}
		}
	}
}

class MyLock{
	public static final Object locka = new Object();
	public static final Object lockb = new Object();
}


public class DeadLockTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Test a = new Test(true);
		Test b = new Test(false);
		Thread t1 = new Thread(a);
		Thread t2 = new Thread(b);
		t1.start();
		t2.start();
	}

}

死锁示例运行结果



-------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值