黑马程序员--多线程

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

多线程

1)概念                

             进程

                  是一个正在执行的程序。

                  每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。

            线程

                 就是进程中的一个独立的控制单元。线程在控制着进程的执行。只要进程中有一个线程在执行,进程就不会结束。

                  一个进程中至少有一个线程。

2)多线线程的实现

            创建线程

                        1、继承thread

                        2、实现Runnable接口

            两种方法区别:

                       1、实现Runnable接口避免了单继承的局限性

                       2、继承Thread类线程代码存放在Thread子类的run方法中

继承方式

/* 
创建两线程,和主线程交替运行。 
*/  
  
//创建线程Test  
class Test extends Thread  
{  
//  private String name;  
    Test(String name)  
    {  
        super(name);  
//      this.name=name;  
    }  
    //复写run方法  
    public void run()  
    {  
        for(int x=0;x<60;x++)  
        System.out.println(Thread.currentThread().getName()+"..run..."+x);  
//      System.out.println(this.getName()+"..run..."+x);  
    }  
}  
  
class  ThreadTest  
{  
    public static void main(String[] args)   
    {  
        new Test("one+++").start();//开启一个线程  
  
        new Test("tow———").start();//开启第二线程  
  
        //主线程执行的代码  
        for(int x=0;x<170;x++)  
        System.out.println("Hello World!");  
    }  
} 

实现Runnable接口的方式

需求:简单的卖票程序。 
多个窗口卖票。 
*/  
class Ticket implements Runnable//extends Thread  
{  
    private  int tick = 100;  
    public void run()  
    {  
        while(true)  
        {  
            if(tick>0)  
            {  
                //显示线程名及余票数  
                System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--);  
            }  
        }  
    }  
}  
  
  
class  TicketDemo  
{  
    public static void main(String[] args)   
    {  
        //创建Runnable接口子类的实例对象  
        Ticket t = new Ticket();  
  
        //有多个窗口在同时卖票,这里用四个线程表示  
        Thread t1 = new Thread(t);//创建了一个线程  
        Thread t2 = new Thread(t);  
        Thread t3 = new Thread(t);  
        Thread t4 = new Thread(t);  
  
        t1.start();//启动线程  
        t2.start();  
        t3.start();  
        t4.start();  
    }  
}  

3)线程状态

                       线程几种状态
                                新建状态:等待启动;
                                就绪状态:调用start启动线程,排队等候执行权
                                运行状态:具有执行资格和执行权。
                                临时状态(阻塞):有执行资格,但是没有执行权。
                                冻结状态:遇到sleep(time)方法和wait()方法时,失去执行资格和执行权,sleep方法时间到或者调用notify()方法时,获得执行资格,变为临时状态。
                                消忙状态:stop()方法,或者run方法结束


 

4)线程安全

           原因:  有共享数据,共享数据被多条语句操作,是在多线程程序中

          解决方案

                     同步代码块:synchronized(对象){被同步的代码}

                     同步函数:把synchronized加在方法上

         同步的前提:
                    1,必须要有两个或者两个以上的线程。
                    2,必须是多个线程使用同一个锁。

同步代码块

/*   
给卖票程序示例加上同步代码块。 
*/  
class Ticket implements Runnable  
{  
    private int tick=100;  
    Object obj = new Object();  
    public void run()  
    {  
        while(true)  
        {  
            //给程序加同步,即锁  
            synchronized(obj)  
            {  
                if(tick>0)  
                {  
                    try  
                    {     
                        //使用线程中的sleep方法,模拟线程出现的安全问题  
                        //因为sleep方法有异常声明,所以这里要对其进行处理  
                        Thread.sleep(10);  
                    }  
                    catch (Exception e)  
                    {  
                    }  
                    //显示线程名及余票数  
                    System.out.println(Thread.currentThread().getName()+"..tick="+tick--);  
                }  
            }     
        }  
    }  
}  

同步函数

class Ticket implements Runnable  
{  
    private int tick=100;  
    Object obj = new Object();  
    public void run()  
    {  
        while(true)  
        {  
            show();  
        }  
    }  
  //直接在函数上用synchronized修饰即可实现同步  
public synchronized void show()  
{  
        if(tick>0)  
        {  
        try  
        {     
            //使用线程中的sleep方法,模拟线程出现的安全问题  
            //因为sleep方法有异常声明,所以这里要对其进行处理  
            Thread.sleep(10);  
        }  
        catch (Exception e)  
        {  
        }  
        //显示线程名及余票数  
        System.out.println(Thread.currentThread().getName()+"..tick="+tick--);  
    }  
}     
}  

                  同步函数用使用的锁
                              函数需要被对象调用。那么函数都有一个所属对象引用。就是this。所以同步函数使用的锁是this。
                                        synchronized(this)
                              静态的同步方法,使用的锁是该方法所在类的字节码文件对象。 类名.class
                                       synchronized(Ticket.class)
                 加同步的单例设计模式 (面试常考)

                      懒汉式,(特点延迟加载,多线程访问会出现安全问题,
                      用同步代码块和同步函数可以解决这个问题,但有些低效,加双重判断提高效率
                      用到的锁是该类所属的字节文件对象)

/* 
加同步的单例设计模式————懒汉式 
*/  
class Single  
{  
    private static Single s = null;  
    private Single(){}  
    public static void getInstance()  
    {  
        if(s==null)  
        {  
            synchronized(Single.class)  
            {  
                if(s==null)  
                    s = new Single();  
            }  
        }  
        return s;  
    }  
}  

5)死锁

           同步嵌套同步,而锁却不同。

//a要b的锁,b要a的锁
class Test implements Runnable
{
   private boolean flag=true;
   Test(boolean flag){
	   this.flag=flag;
   }
@Override
public void run() {
	// TODO Auto-generated method stub
	if(flag){
		while(true){
			synchronized (MyLock.locka) {
				System.out.println("if---a");
				synchronized (MyLock.lockb) {
					System.out.println("if----b");
				}
				
			}

		}
	}
	else{
		while(true)
		{
			synchronized (MyLock.lockb) {
				System.out.println("else``````b");
				synchronized (MyLock.locka) {
					System.out.println("else```````a");
				}
			}
			
			
		}
	}
	
}	
}
class MyLock
{
	static Object locka = new Object();
	static Object lockb = new Object();
}
class Deadlock {
  public static void main(String[] args) {
	Thread t1=new Thread(new Test(true));
	Thread t2=new Thread(new Test(false));
	t1.start();
	t2.start();
}
}

6)线程间的通信

* 
生产者生产商品,供消费者使用 
有两个或者多个生产者,生产一次就等待消费一次 
有两个或者多个消费者,等待生产者生产一次就消费掉 
 
*/  
  
import java.util.concurrent.locks.*;  
  
class Resource   
{     
    private String name;  
    private int count=1;  
    private boolean flag = false;  
      
    //多态  
    private Lock lock=new ReentrantLock();  
  
    //创建两Condition对象,分别来控制等待或唤醒本方和对方线程  
    Condition condition_pro=lock.newCondition();  
    Condition condition_con=lock.newCondition();  
  
    //p1、p2共享此方法  
    public void setProducer(String name)throws InterruptedException  
    {  
        lock.lock();//锁  
        try  
        {  
            while(flag)//重复判断标识,确认是否生产  
                condition_pro.await();//本方等待  
  
            this.name=name+"......"+count++;//生产  
            System.out.println(Thread.currentThread().getName()+"...生产..."+this.name);//打印生产  
            flag=true;//控制生产\消费标识  
            condition_con.signal();//唤醒对方  
        }  
        finally  
        {  
            lock.unlock();//解锁,这个动作一定执行  
        }  
          
    }  
  
    //c1、c2共享此方法  
    public void getConsumer()throws InterruptedException  
    {  
        lock.lock();  
        try  
        {  
            while(!flag)//重复判断标识,确认是否可以消费  
                condition_con.await();  
  
            System.out.println(Thread.currentThread().getName()+".消费."+this.name);//打印消费  
            flag=false;//控制生产\消费标识  
            condition_pro.signal();  
        }  
        finally  
        {  
            lock.unlock();  
        }  
  
    }  
}  
  
//生产者线程  
class Producer implements Runnable   
{  
    private Resource res;  
    Producer(Resource res)  
    {  
        this.res=res;  
    }  
    //复写run方法  
    public void run()  
    {  
        while(true)  
        {  
            try  
            {  
                res.setProducer("商品");  
            }  
            catch (InterruptedException e)  
            {  
            }  
        }  
    }  
}  
  
//消费者线程  
class Consumer implements Runnable  
{  
    private Resource res;  
    Consumer(Resource res)  
    {  
        this.res=res;  
    }  
    //复写run  
    public void run()  
    {  
        while(true)  
        {  
            try  
            {  
                res.getConsumer();  
            }  
            catch (InterruptedException e)  
            {  
            }  
        }  
    }  
  
}  
  
class  ProducerConsumer  
{  
    public static void main(String[] args)   
    {  
        Resource res=new Resource();  
  
        new Thread(new Producer(res)).start();//第一个生产线程 p1  
        new Thread(new Consumer(res)).start();//第一个消费线程 c1  
  
        new Thread(new Producer(res)).start();//第二个生产线程 p2  
        new Thread(new Consumer(res)).start();//第二个消费线程 c2  
    }  
}  


          

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值