黑马程序员_多线程

  ------- android培训java培训、期待与您交流! ----------


一 进程和线程概念
1 进程:进程就是正在执行的程序,每个进程执行都有一个执行顺序,该顺序就是一个控制单元或执行路径。
2 线程:线程就是进程中的一个独立的控制单元,线程控制着进程的执行。一个进程中至少有一个线程。
3 java虚拟机启动的时候会启动一个进程,该进程会有一个线程控制者程序的执行,线程执行的代码存在main函数中,该线程称为主线程。
4 多线程:一个进程能有多个线程,多线程能提高效率。


二 线程的几种状态:
(1)线程创建:创建Thread或Thread子类对象
(2)线程运行:具备运行资格,有执行权,方法start()
(3)线程阻塞:具备运行资格没有执行权
(4)线程冻结:没有执行资格,通过sleep(int time);wait();方法
(5)线程消亡:stop();程序结束


三 创建线程(两种方式)
1 继承Thread类,复写run()方法,线程运行的代码在run()方法中。调用start()方法执行线程。
(1)run()仅仅只是调用run()方法而没有执行线程
(2)start()执行线程并调用run()方法
例如:

class XianCheng extends Thread
{
	public void run()
	{
		System.out.println("线程运行");
	}
}
class ThreadDemo
{
	public static void main(String[] args)
	{
		XianCheng xc=new XianCheng();//创建线程
		xc.start();//执行线程
	}
}

2.创建类实现Runnable接口,覆盖run()方法,创建Thread线程对象,并将Runnable接口子类对象作为参数传给Thread的构造方法,调用Thread对象start()方法
例如:

class XianCheng implements Runnable
{
	public void run()
	{
		System.out.println("线程运行");
	}
}
class ThreadDemo
{
	public static void main(String[] args)
	{
		XianCheng xc=new XianCheng();//创建Runable子类对象
		Thread t=new Thread(xc);//创建线程并将Runable的子类对象传进来
		t.start();//执行线程
	}
}

3 二种方式的区别
(1)继承Thread类方法,有继承的局限性,因为java只支持单继承。多线程运行的代码放在Thread类的子类的run()方法中。
(2)实现Runnable接口方法,java支持多实现,所以用这种方法提高了扩展性。此方法多线程运行的代码放在Runnable接口子类的run()方法中。

4 线程同步的方式
(1)同步代码块,同步代码块用的锁是任意对象都可以
     格式:
synchronized(对象//任意对象)
{
需要被同步的语句;
}
(2)同步函数,将synchronized关键字放在函数的返回值前面,同步函数用的锁是this
     静态同步函数,静态同步函数用的锁是该类的字节码文件对象 类名.class
线程同步例子:

class ThreadDemo
{
	public static void main(String[] args) 
	{
		//创建Runnable接口子类对象
		SaleTicket st=new SaleTicket();
		//创建线程将对象传给Thread类的构造方法
		Thread t1=new Thread(st);
		Thread t2=new Thread(st);
		Thread t3=new Thread(st);
		Thread t4=new Thread(st);
		//线程执行
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}

class SaleTicket implements Runnable
{
	//定义100张票
	private int ticket=100;
	//覆盖run()方法
	public void run()
	{
		//无线循环
		while(true)
		{
			//加同步,同步的锁是SaleTicket类的文件对象
			synchronized(SaleTicket.class)
			{
				if(ticket>0)
				{
					//制作一个线程安全隐患
					try{Thread.currentThread().sleep(5);} catch(Exception e){}
					System.out.println(Thread.currentThread().getName()+"正在售票第"+ticket--+"张票");
				}
			}		
		}
	}
}

5 懒汉式的线程同步

代码如下:

class Single
{
	private Single(){}//将构造函数私有不给外界创建对象
	private static Single s=null;//本类创建对象,用静态修饰,方便getInstance()访问
	public static Single getInstance()
	{
		//双层判断,只要s创建过对象就不再判断锁了,稍微高效
		if(s==null)
		{
			//在这里加锁,防止多个线程同时执行下面的语句
			synchronized(Single.class)
			{
				//如果为空,创建对象
				if(s==null)
					s=new Single();
			}
		}
		return s;
	}
} 

6 死锁,同步中嵌套同步很容易发生死锁

代码示例:

public void run()
{
	//如果一个线程执行if中代码,而另一个线程执行else代码
	if(flag)
	{
		//此线程a锁中嵌套b锁
		synchronized(Mylock.locka)
		{
			System.out.println("if locka");
			synchronized(Mylock.lockb)
			{
				System.out.println("if lockb");
			}
		}
	}
	else
	{
		//此线程b锁中嵌套a锁,此时就很容易发生死锁
		synchronized(Mylock.lockb)
		{
			System.out.println("else lockb");
			synchronized(Mylock.locka)
			{
				System.out.println("else locka");
			}
		}
	}
}

五 通信间的线程
1 Object中应用线程的方法
  wait(),notify(),notifyAll()这些方法要使用在同步中。

2 定义在Object的原因
(1)这些方法在操作线程时,都必须标识他们所操作线程中的锁
(2)只有同一个锁上的线程等待,能被同一锁的线程唤醒
(3)而锁可以是任意对象,所以定义在Object中

3 等待中的线程在线程池中,一般线程唤醒的是线程中的第一个线程
例子:创建两个线程,一个负责赋值,一个赋值取值,操作同一资源对象。代码如下:

class  ThreadDemo
{
	public static void main(String[] args) 
	{
		//创建资源对象
		Res r=new Res();
		//创建两个线程,一个负责给资源赋值,一个负责取值
		new Thread(new Input(r)).start();
		new Thread(new Output(r)).start();

	}
}
//定义一个资源类
class Res
{
	private String name;
	private String sex;
	private boolean flag;
	//同步函数
	public synchronized void set(String name,String sex)
	{
		//判断标记,资源中没值就赋值,有值线程就等待
		if(flag)
			try{wait();} catch(Exception e){}
		this.name=name;
		this.sex=sex;
		flag=true;//赋值之后把标记改为true,代表有值了
		notify();//把对方唤醒
	}
	//同步函数
	public synchronized void get()
	{
		//判断标记,资源中有值就取,没值线程就等待
		if(!flag)
			try{wait();} catch(Exception e){}
		System.out.println(name+":::"+sex);
		flag=false;//取值后把标记改为false
		notify();//唤醒对方
	}
}
//定义一个赋值的线程
class Input implements Runnable
{
	//将资源传递给构造方法
	private Res r;
	Input(Res r)
	{
		this.r=r;
	}
	public void run()
	{
		int num=0;
		while(true)
		{
			if(num==0)
				r.set("lisi","man");
			else
				r.set("李四","男");
			num=(num+1)%2;
		}
	}
}
//定义一个取值的线程
class Output implements Runnable
{
	//将资源传递给构造方法
	private Res r;
	Output(Res r)
	{
		this.r=r;
	}
	public void run()
	{
		while(true)
		{
			r.get();
		}
	}
}

4 JDK1.5版本之后,提供了多线程升级解决方案
(1)将synchronized变为显示的Lock
(2)将Object中的wait(),notify(),notifyAll()替换成了Condition对象,更灵活的应用等待唤醒机制


六 操作线程的其他方法
1 停止线程:stop()(此方法已经过时),只有一种方法,就是run()方法结束,一般run()方法中,定义的都是循环语句,所以我们可以控制循环使线程结束。

2 中断线程:interrupt(),此方法可以将处于冻结状态的线程强制回到运行状态(清除线程的冻结状态)

3 守护线程:setDeamon()后台线程,当前台线程结束后,后台线程自动结束。此方法必须在线程执行前调用。

4 等待线程停止:jion()方法,放某个线程执行到join()方法时,该线程会冻结,等到调用join()方法的线程结束,该线程才回到运行状态。

5 优先级:setPriority(),此方法可以设置线程的优先级,优先级越高,CPU执行该线程的频率越高。默认是5。

6 yield():临时停止,暂停线程




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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值