多线程

第十一天
线程和进程
进程:是一个正在执行中的程序。
  每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。
线程:就是进程中的一个独立的控制单元。
  线程在控制着进程的执行。
一个进程中至少有一个线程。

创建线程方式一:(Thread)
子类覆盖父类中的run方法,将线程运行的代码存放在run中。
建立子类对象的同时线程也被创建。
通过调用start方法开启线程。

class DemoA extends Thread
{
	public void run(){}//覆盖run方法
}
class DemoB
{
	public static void main(String[] args) 
	{
		Thread t1 =new DemoA();//创建线程对象
		Thread t2 =new DemoA();//创建线程对象
		ti.start();//启动线程,run方法无法启动线程
		t2.start();//启动线程
	}
}


创建线程方式二(Runnable)
实现Runnable接口
子类覆盖接口中的run方法。
通过Thread类创建线程,并将实现了Runnable接口的子类对象作为参数传递给Thread类的构造函数。
Thread类对象调用start方法开启线程。

class DemoA implements Runnable//好处:还可以继承其他类。避免了单继承的局限性
{
	public void run(){}//覆盖run方法
}
class DemoB
{
	public static void main(String[] args) 
	{
		Thread t1 =new DemoA();//创建线程对象
		Thread t2 =new DemoA();//创建线程对象
		ti.start();//启动线程,run方法无法启动线程,仅仅对象调用方法而已
		t2.start();//启动线程
	}
}


线程的四种状态:

sleep方法需要指定睡眠时间,单位是毫秒。
一个特殊的状态:就绪。具备了执行资格,但是还没有获取资源。

 

多线程的安全为题:
导致安全问题的出现的原因:
多个线程访问出现延迟。//cpu随机切换导致
线程随机性 。
注:线程安全问题在理想状态下,不容易出现,但一旦出现对软件的影响是非常大的。
解决线程安全问题:
同步(synchronized)//降低了效率
格式:
synchronized(对象)
{
 需要同步的代码;
}
同步可以解决安全问题的根本原因就在那个对象上。
该对象如同锁的功能。

同步的特点
同步的前提:
同步需要两个或者两个以上的线程。
多个线程使用的是同一个锁。
未满足这两个条件,不能称其为同步。

同步的弊端:
当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。
同步函数
格式:
在函数上加上synchronized修饰符即可。
同步函数用的this锁

死锁:
同步中嵌套同步。

class Test implements Runnable
{
	private boolean flag;
	Test(boolean flag)
	{
		this.flag = flag;
	}

	public void run()
	{
		if(flag)
		{
			while(true)
			{
				synchronized(MyLock.locka)//同步里面嵌套同步
				{
					System.out.println(Thread.currentThread().getName()+"...if locka ");
					synchronized(MyLock.lockb)
					{
						System.out.println(Thread.currentThread().getName()+"..if lockb");					
					}
				}
			}
		}
		else
		{
			while(true)
			{
				synchronized(MyLock.lockb)//同步里面嵌套同步
				{
					System.out.println(Thread.currentThread().getName()+"..else lockb");
					synchronized(MyLock.locka)
					{
						System.out.println(Thread.currentThread().getName()+".....else locka");
					}
				}
			}
		}
	}
}
class MyLock
{
	static Object locka = new Object();
	static Object lockb = new Object();
}
class  DeadLockTest
{
	public static void main(String[] args) 
	{	
		Thread t1 = new Thread(new Test(true));
		Thread t2 = new Thread(new Test(false));
		t1.start();
		t2.start();
	}
}


线程间的通信:
当多个线程炒作一个共享资源时候。
银行随机存取问题实例:
等待唤醒机制:

class  BankTest
{
	public static void main(String[] args) 
	{
		ZhangHu zhanghu =new ZhangHu();
		IntCun Int = new IntCun(zhanghu);
		OutQu Out = new OutQu(zhanghu);
		Thread t1 = new Thread(Int);
		Thread t2 = new Thread(Out);
		t1.start();
		t2.start();
		
	}
}
class ZhangHu //同一个资源。
{
	private long money = 0;
	private boolean flag=true;
	public synchronized void set(long money)//存入线程所运行代码。
	{
		if(flag)	
		{
		try{this.wait();}catch(Exception e){}
		this.money += money;
		 System.out.println("存款成功,"+"余额为"+this.money);	
		}
		// System.out.println("检测...........");
		flag = false; 
		this.notify();//两个线程以上就将notify()换成notify。或者看下面代码lock锁		
	}
	public synchronized void out(long money)//取出线程所运行代码。
	{
		if(!flag)
		{
			if(this.money>money)
			{
				try{
					this.wait();
				   }
				catch(Exception e)
					{}
				this.money-=money;
				System.out.println("取钱成功,"+"余额为"+this.money);
				
			}
			else
			{
				System.out.println("取钱失败,"+"余额为"+this.money);
			}
		}
		flag = true;
		this.notify();	//两个以上线程操作此方法就将notify()换成notifyAll()。或者看下面代码lock锁		
	}
}
class IntCun implements Runnable//存入,转入。
{
	private ZhangHu  zhanghu;//存入同一个账户。使两个线程操作共享资源
	
	IntCun(ZhangHu  zhanghu)
	{
		this.zhanghu =zhanghu;
	}
	long money =(long)(Math.random()*2000);
	public void run()//存钱的线程方法,里面调用set存入方法
	{
		while(true)
		{
			try
			{
				Thread.sleep((int)(Math.random()*2000));//随机时间存一次钱
				//System.out.println("存入钱数*******"+money);
				zhanghu.set(money);//随机存款	
			}
			catch (Exception e)
			{
			}			
		 }
	}
}
class OutQu implements Runnable//取出。
{
	private ZhangHu  zhanghu;//取出的账户,使两个线程操作共享资源
	OutQu(ZhangHu  zhanghu)
	{
		this.zhanghu =zhanghu;
	}
	long money =(long)(Math.random()*2000);//定义随机钱数
	public void run()//取钱的线程方法,里面调用out()取出方法。
	{
		while(true)
		{	
			try
			{
			Thread.sleep((int)(Math.random()*2000));//随机时间取一次钱
			//System.out.println("取出钱数....."+money);
			zhanghu.out(money);//随机取款			
			}
			catch (Exception e)
			{
			}
		}
	}
}


1.5新特性:
接口 Lock://替换synchronized
将synchronized 替换成了Lock接口。
 将隐式锁,升级成了显示锁。
Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。
此实现允许更灵活的结构,可以具有差别很大的属性,可以支持多个相关的 Condition 对象。
void lock()
          获取锁。
void unlock()
          释放锁。
接口Condition://替代了 Object 监视器方法的使用。
Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,
以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set(wait-set)。
其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。
void await()
          造成当前线程在接到信号或被中断之前一直处于等待状态。
void signal()
          唤醒一个等待线程。
void signalAll()
          唤醒所有等待线程
替代上面代码:

import java.util.concurrent.locks.*;
class  BankTest
{
	public static void main(String[] args) 
	{
		ZhangHu zhanghu =new ZhangHu();
		IntCun Int = new IntCun(zhanghu);
		OutQu Out = new OutQu(zhanghu);
		Thread t1 = new Thread(Int);
		Thread t2 = new Thread(Int);
		Thread t3 = new Thread(Out);
		Thread t4 = new Thread(Out);
		t1.start();
		t2.start();
		t3.start();
		t4.start();		
	}
}
class ZhangHu //同一个资源。
{
	private long money = 0;
	private boolean flag=true;
	private Lock lock = new ReentrantLock();
    private Condition condition_int = lock.newCondition();
	private Condition condition_out = lock.newCondition();
	public  void set(long money)
	{
		String name =Thread.currentThread().getName();//获取线程名称,线程0和线程1
		lock.lock();
		try
		{
			if(flag)	
			{
				try
				{
					condition_int.await();
				}
				catch (Exception e)
				{
				}	
			this.money += money;
			System.out.println(name+"存款成功,"+"余额为"+this.money);	
			}
			// System.out.println("检测...........");
			flag = false;
			condition_out.signal();//唤醒对方一个线程
		}		
		finally
		{
			lock.unlock();//释放锁的动作一定要执行。
		}
}
/*
格式:try()finally()
	 
	lock.lock();
     try 
	 {
       while()
         notFull.await();//要try,不try的话就在函数上抛,让下面调用的处理
      
       notEmpty.signal();
     }
	 finally 
	 {
       lock.unlock();
     }
*/							
	public synchronized void out(long money)
	{
		String name =Thread.currentThread().getName();//获取线程名称,线程2和线程3
		lock.lock();
		try
		{
				if(!flag)
				{
				if(this.money>money)
				{
				try
				{
				condition_out.await();
				}
				catch (Exception e)
				{
				}
				this.money-=money;
				System.out.println(name+"取钱成功,"+"余额为"+this.money);
				
				}
				else
				{
				System.out.println(name+"取钱失败,"+"余额为"+this.money);
				}
			
		}
		flag = true;
		condition_int.signal();//唤醒对方一个线程
		}			
		finally
		{
			lock.unlock();//释放锁的动作一定要执行。
		}
	
        
	}
}
class IntCun implements Runnable//存入,转入。
{
	private ZhangHu  zhanghu;//存入的账户
	
	IntCun(ZhangHu  zhanghu)
	{
		this.zhanghu =zhanghu;
	}
	long money =(long)(Math.random()*2000);
	public void run()//存钱的线程方法
	{
		while(true)
		{
			try
			{
				Thread.sleep((int)(Math.random()*2000));//随机时间存一次钱
				//System.out.println("存入钱数*******"+money);
				zhanghu.set(money);//随机存款	
			}
			catch (Exception e)
			{
			}			
		 }
	}
}
class OutQu implements Runnable//取出。
{
	private ZhangHu  zhanghu;//取出的账户
	OutQu(ZhangHu  zhanghu)
	{
		this.zhanghu =zhanghu;
	}
	long money =(long)(Math.random()*2000);//定义随机钱数
	public void run()//取钱的线程方法
	{
		while(true)
		{	
			try
			{
			Thread.sleep((int)(Math.random()*2000));//随机时间取一次钱
			//System.out.println("取出钱数....."+money);
			zhanghu.out(money);//随机取款			
			}
			catch (Exception e)
			{
			}
		}
	}
}


 

停止线程:
stop方法已经过时。
如何停止线程?
只有一种,run方法结束。
开启多线程运行,运行代码通常是循环结构。
只要控制住循环,就可以让run方法结束,也就是线程结束。

特殊情况:
当线程处于了冻结状态。
就不会读取到标记。那么线程就不会结束。

当没有指定的方式让冻结的线程恢复到运行状态是,这时需要对冻结进行清除。
强制让线程恢复到运行状态中来。这样就可以操作标记让线程结束。
Thread类提供该方法 interrupt();

class StopThread implements Runnable
{
	private boolean flag =true;
	public  void run()
	{
		while(flag)
		{	try
			{
				wait();//让线程处于冻结状态,另一个线程读不到标记,就挂了。用中断interrupt();来解决。
			}
			catch (InterruptedException e)
			{
				flag = false;//让标记为假,让程序停止循环,程序结束
			}
			System.out.println(Thread.currentThread().getName()+"....run");
		}
	}
	public void changeFlag()
	{
		flag = false;
	}
}
class  StopThreadDemo
{
	public static void main(String[] args) 
	{
		StopThread st = new StopThread();
		
		Thread t1 = new Thread(st);
		Thread t2 = new Thread(st);
		t1.start();
		t2.start();
		int num = 0;
		while(true)
		{
			if(num++ == 60)
			{
				//st.changeFlag();
				t1.interrupt();
				t2.interrupt();
				break;
			}
			System.out.println(Thread.currentThread().getName()+"......."+num);
		}
		System.out.println("over");
	}
}


守护线程(后台线程):
当所有前台线程结束后,后台线程自动结束。

class StopThread implements Runnable
{
	private boolean flag =true;
	public  void run()
	{
		while(flag)
		{	
			System.out.println(Thread.currentThread().getName()+"....run");
		}
	}
	public void changeFlag()
	{
		flag = false;
	}
}
class  StopThreadDemo
{
	public static void main(String[] args) 
	{
		StopThread st = new StopThread();
		
		Thread t1 = new Thread(st);
		Thread t2 = new Thread(st);
		t1.setDaemon(true);//守护线程。
		t2.setDaemon(true);//不管守护线程是否在冻结状态,主线程结束,它就结束。
		t1.start();
		t2.start();
		int num = 0;
		while(true)
		{
			if(num++ == 60)
			{
				//st.changeFlag();
				break;
			}
			System.out.println(Thread.currentThread().getName()+"......."+num);
		}
		System.out.println("over");
	}
}


join:
当A线程执行到了B线程的.join()方法时,A就会等待。等B线程都执行完,A才会执行。
join可以用来临时加入线程执行。
优先级:Thread.MAX_PRIORITY,CPU执行权大小

class Demo implements Runnable
{
	public void run()
	{
		for(int x=0; x<70; x++)
		{
			System.out.println(Thread.currentThread().toString()+"....."+x);
			Thread.yield();
		}
	}
}
class  JoinDemo
{
	public static void main(String[] args) throws Exception
	{
		Demo d = new Demo();
		Thread t1 = new Thread(d);
		Thread t2 = new Thread(d);
		t1.start();
		//t1.setPriority(Thread.MAX_PRIORITY);
		t2.start();
		//t1.join();//拿到CPU执行权,它从谁手里拿到执行权,那个被那执行权的就要等它执行完才执行。谁给谁等
		for(int x=0; x<80; x++)
		{
			//System.out.println("main....."+x);
		}
		System.out.println("over");
	}
}


wait和sleep的区别:
wait:释放cpu执行权,释放同步中锁。
sleep:释放cpu执行权,不释放同步中锁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值