黑马程序员_多线程

---------------------- ASP.Net+Android+IOS开发 .Net培训 、期待与您交流! ----------------------
1.进程和线程
进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以有多个线程。比如在Windows系统中,一个运行的xx.exe就是一个进程。
Java程序的进程里有几个线程:主线程, 垃圾回收线程(后台线程)
线程是指进程中的一个执行任务(控制单元),一个进程中可以运行多个线程,多个线程可共享数据。
多进程:操作系统中同时运行的多个程序;
多线程:在同一个进程中同时运行的多个任务;
一个进程至少有一个线程,为了提高效率,可以在一个进程中开启多个控制单元。 
并发运行。如:多线程下载软件。  
2.进程与线程的区别:
(1).进程有独立的进程空间,进程中的数据存放空间(堆空间和栈空间)是独立的。
(2).线程的堆空间是共享的,栈空间是独立的,线程消耗的资源也比进程小,相互之间可以影响的
3.创建线程的方式
实现多线程可以通过继承Thread类和实现Runnable接口。
(1)继承Thread
定义一个类继承Thread类
复写Thread类中的public void run()方法,将线程的任务代码封装到run方法中
直接创建Thread的子类对象,创建线程
调用start()方法,开启线程(调用线程的任务run方法)
另外可以通过Thread的getName()获取线程的名称。
(2)实现Runnable接口;
定义一个类,实现Runnable接口;
覆盖接口的public void run()的方法,将线程的任务代码封装到run方法中;
创建Runnable接口的子类对象
将Runnabl接口的子类对象作为参数传递给Thread类的构造函数,创建Thread类对象
(原因:线程的任务都封装在Runnable接口子类对象的run方法中,所以要在线程对象创建时就必须明确要运行的任务)
调用start()方法,启动线程。
两种方法的区别
1)实现Runnable接口避免了单继承的局限性
(2)继承Thread类线程代码存放在Thread子类的run方法中
实现Runnable接口线程代码存放在接口的子类的run方法中;
在定义线程时,建议使用实现Runnable接口,因为几乎所有多线程都可以使用这种方式实现。
两种方式实现售票的例子:
方法一:
class MyThread1 extends Thread {
	private Integer num = 50;
	public MyThread1(String name) {
		super(name);
	}
	public void run() {
		int count = 0;
		for (int i = 1; i <= 200; i++) {
			if(num > 0){
			count ++;
	System.out.println(getName() + "卖出第--->" + num-- +"张票");
			}
		}
		System.err.println(getName()+"卖了"+ count +"张票" );
	}
}
方法二:
class MyThread2 implements Runnable{
	private Integer num = 50;
	public void run() {
		int count = 0;
		for (int i = 0; i < 200 ; i++) {
			if(num > 0){
				count ++;
	System.out.println(Thread.currentThread().getName()
		 + "卖出第--->" + num-- +"张票");
			}
		}
	System.err.println(Thread.currentThread().getName()
		 +  "卖了"+ count +"张票" );
	}
}
4.线程的生命周期:
5.线程的几种状态:
新建:new一个Thread对象或者其子类对象就是创建一个线程,当一个线程对象被创建,但是没有开启,这个时候,
只是对象线程对象开辟了内存空间和初始化数据。        
就绪:新建的对象调用start方法,就开启了线程,线程就到了就绪状态。在这个状态的线程对象,具有执行资格,没有执行权。
运行:当线程对象获取到了CPU的资源。在这个状态的线程对象,既有执行资格,也有执行权。
冻结:运行过程中的线程由于某些原因(比如wait,sleep),释放了执行资格和执行权。当然,他们可以回到运行状态。只不过,不是直接回到。而是先回到就绪状态。
死亡:当线程对象调用的run方法结束,或者直接调用stop方法,就让线程对象死亡,在内存中变成了垃圾。
6.sleep()和wait()的区别:
(1)这两个方法来自不同的类,sleep()来自Thread类,和wait()来自Object类。
(2)sleep是Thread的静态类方法,谁调用的谁去睡觉,即使在a线程里调用了b的sleep方法,实际上还是a去睡觉,
要让b线程睡觉要在b的代码中调用sleep。而wait()是Object类的非静态方法
(3)sleep()释放资源不释放锁,而wait()释放资源释放锁;
(4)使用范围:wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用
7.线程同步(synchronized)
格式:
synchronized(对象)
{
需要同步的代码;
}
同步可以解决安全问题的根本原因就在那个对象上。
该对象如同锁的功能。
同步的前提:
(1)必须保证有两个以上线程
(2)必须是多个线程使用同一个锁,即多条语句在操作线程共享数据
(3)必须保证同步中只有一个线程在运行
好处:解决了多线程的安全问题
弊端:多个线程需要判断锁,消耗资源,程序的效率会降低
同步函数使用的锁就是调用该函数的对象即this
静态同步函数使用的锁是类名.class,也就是该类的字节码对象。因为静态进内存时,内存中没有本类对象,但一定有该类对应的字节码文件对象。
示例:
class Test implements Runnable//extends Thread  
{  
    private static int tick = 100;  
    boolean flag = true;  
    Object obj = new Object();  
    public void run()  
    {  
        if(flag)  
        {  
        while(true)  
        {  
            synchronized(Test.class)//如果验证非静态同步函数,传入this  
            {  
                if(tick>0)  
                {  
                      
                    try  
                    {  
                    Thread.sleep(10);  
                    }  
                    catch (Exception e)  
                    {}/**/  
                  
                    System.out.println(Thread.currentThread()+"....."+tick--);  
                }  
  
  
            }  
              
        }  
        }  
        else   
            while(true)  
                show();  
    }  
    public static synchronized void show()//静态同步函数  
    {  
        if(tick>0)  
                {  
                      
                    try  
                    {  
                    Thread.sleep(10);  
                    }  
                    catch (Exception e)  
                    {}/**/  
                  
                    System.out.println(Thread.currentThread()+"....."+tick--);  
                }  
    }  
}  
class  ThreadDemo  
{  
    public static void main(String[] args)   
    {  
        Test t = new Test();  
        new Thread(t).start();  
        try{Thread.sleep(10);}catch(Exception e){}  
        t.flag = false;  
        new Thread(t).start();  
      
    }  
}  
8.死锁
(1)是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。 由于资源占用是互斥的,当某个进程提出申请资源后,使得有关进程在无外力协助下,永远分配不到必需的资源而无法继续运行,这就产生了一种特殊现象:死锁。”
示例:
class Test implements Runnable  
{  
    private boolean flag;  
    Test(boolean flag)  
    {  
        this.flag = flag;  
    }  
    public void run()  
    {  
        if(flag)  
        {  
            while(true)  
            {  
                synchronized(LockClass.locka)  
                {  
                    System.out.println("if locka");  
                    synchronized(LockClass.lockb)  
                    {  
                        System.out.println("if lockb");  
                    }  
                }  
            }  
        }  
        else  
        {  
            while(true)  
            {  
                synchronized(LockClass.lockb)  
                {  
                    System.out.println("else lockb");  
                    synchronized(LockClass.locka)  
                    {  
                        System.out.println("else locka");  
                    }  
                }  
            }  
        }  
    }  
}  
class LockClass  
{  
    public static LockClass locka = new LockClass();  
    public static LockClass lockb = new LockClass();  
}  
  
  
class  DeadLockDemo  
{  
    public static void main(String[] args)   
    {  
        new Thread(new Test(true)).start();  
        new Thread(new Test(false)).start();  
    }  
}  
( 2)wait()、sleep()、notify()、notifyAll()比较
wait():使一个线程处于等待状态,并且释放所持有的对象的lock。 
sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。 
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,
 而是由JVM确定唤醒哪个线程(一般是最先开始等待的线程),而且不是按优先级。 
Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。

9.生产者和消费者示例:
class Resource  
{  
    private String name;  
    private int count = 1;  
    private boolean flag = false;  
  
  
    public synchronized void set(String name)  
    {  
        while(flag)//定义while判断标记,让被唤醒的线程再一次判定标记  
            try{this.wait();}catch(Exception e){}  
        this.name = name;  
        System.out.println(Thread.currentThread().getName()+"...生产者"+this.name+"---"+count++);  
        flag = true;  
        this.notifyAll();//需要唤醒对方线程,只用notify,容易出现只唤醒本方线程的情况。导致程序中的所有线程都等待。  
  
  
    }  
    public synchronized void out()  
    {  
        while(!flag)  
            try{this.wait();}catch(Exception e){}  
        System.out.println(Thread.currentThread().getName()+"...消费者......"+this.name+"---"+count);  
        flag = false;  
        this.notifyAll();  
    }  
}  
class Producer implements Runnable  
{  
    private Resource r;  
    Producer(Resource r)  
    {  
        this.r = r;  
    }  
    public void run()  
    {  
        while(true)  
        {  
            r.set("+ 商品 + ");  
        }  
    }  
}  
class Consumer implements Runnable  
{  
    private Resource r;  
    Consumer(Resource r)  
    {  
        this.r = r;  
    }  
    public void run()  
    {  
        while(true)  
        {  
            r.out();  
        }  
    }  
}  
  
  
class  ProConDemo  
{  
    public static void main(String[] args)   
    {  
        Resource r = new Resource();  
        new Thread(new Producer(r)).start();  
        new Thread(new Producer(r)).start();  
        new Thread(new Consumer(r)).start();  
        new Thread(new Consumer(r)).start();  
    }  
}  
10.停止线程:run方法结束。开启多线程运行,运行代码通常都是循环结构,只要控制住循环,就可以让线程结束。
当线程处于冻结状态,就不会读取到标记,那么线程就不会结束。
当没有指定的方式让冻结的线程恢复到运行状态时,这时就需要对冻结进行清除。强制让线程恢复到运行状态中来。
这样就可以操作标记让线程结束。Thread类中提供了该方法 interrupt();

11.多线程join方法:
void join() 等待该线程终止。
void join(long millis)  等待该线程终止的时间最长为 millis 毫秒。
throws InterruptedException         
特点:当A线程执行到B线程的join方法时,A就会等待B线程都执行完,A才会执行
作用: join可以用来临时加入线程执行;
12.多线程优先级:yield()方法
yield():暂停当前正在执行的线程对象,并执行其他线程
setPriority(int newPriority):更改线程优先级
int getPriority() 返回线程的优先级。
String toString() 返回该线程的字符串表示形式,包括线程名称、优先级和线程组
(1)MAX_PRIORITY:最高优先级(10级)
(1)Min_PRIORITY:最低优先级(1级)
(1)Morm_PRIORITY:默认优先级(5级)



---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值