黑马程序员——Java多线程

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

多线程
创建线程的第一种方式:
1,定义类继承Thread;
2,复写Thread类中的run方法;
3,调用线程的start方法,该方法两个作用:启动线程,调用run方法。
如:

class XianCheng extends Thread//继承Thread类
{
	public void run()//覆盖run方法
	{
		for(int x=0;x<100;x++)
			System.out.println("x...num="+x);
	}
}

class JiChengDemo
{
	public static void main(String[] args)
	{
		XianCheng xc =new XianCheng();
		
		xc.start();
		
		for(int y=101;y<200;y++)
			System.out.println("y...num="+y);
	}
}
线程运行状态:
         被创建:等待启动,调用start启动。
         运行状态:具有执行资格和执行权。
         临时状态(阻塞):有执行资格,但是没有执行权。
         冻结状态:遇到sleep(time)方法和wait()方法时,失去执行资格和执行权,sleep方法时间到或者调用notify()方法时,
  获得执行资格,变为临时状态。
         消忙状态:stop()方法,或者run方法结束。
注:当已经从创建状态到了运行状态,再次调用start()方法时,就失去意义了,java运行时会提示线程状态异常。

图解:




static Thread currentThread():获取当前线程对象。
getName():获取线程名称。
设置线程名称:setName或构造函数。

创建线程的第二种方式:实现Runable接口
步骤:
1,定义类实现Runable接口;
2,覆盖Runable接口中的run方法;
3,通过Thread类建立线程对象;
4,将Runable接口的子类对象作为实际参数传递给Thread类的构造函数;
5,调用Thread类的start方法开启线程并调用Runable接口子类的方法。
如:

class XianCheng implements Runnable//实现Runnable接口
{
	public void run()//覆盖Runnable中的run方法
	{
		for(int x=0;x<100;x++)
			System.out.println("x...num="+x);
	}
}


class ShiXianDemo
{
	public static void main(String[] args)
	{
		XianCheng xc =new XianCheng();
		Thread t1 = new Thread(xc);
		t1.start();
		
		for(int y=101;y<200;y++)
			System.out.println("y...num="+y);
	}
}

实现方式与继承方式的区别:
继承Thread:线程代码存放在Thread子类run方法中;
实现Runable:线程代码存放在接口子类的run方法中。

实现方式的好处:避免了单继承的局限性。在定义线程时,建议使用实现方式。

Java中对于多线程的安全问题提供了专业的解决方式:

同步代码块:
synchronized
{
需要被同步的代码;
}
同步的前提:
1,必须要有两个或两个以上的线程。
2,必须是多个线程使用同一个锁。

同步的好处:解决了多线程的安全问题。
同步的弊端:多个线程需要判断锁,较为消耗资源。
同步函数被静态修饰后,使用的锁是该方法所在类的字节码文件,即类名.class,该对象的类型是Class。

多线程——单利设计模式——懒汉式:
class single
{
	private static Single s = null;
	private single(){ }


	public static Single getInstance( )
	{
		if(s==null)
		{
			synchronized(Single.class)//该处的锁为类的字节码文件
			{
				if(s==null)
				{
					s = new Single();
				}		
			}
			return s;
		}
	}
}





死锁:死锁出现的原因是同步中嵌套同步。
死锁举例:
class XianCheng implements Runnable
{
	private boolean b;
	XianCheng(boolean b)
	{
		this.b=b;
	}
	public void run()//覆盖run方法。
	{
		if(b)
		{
			synchronized(MyLock.asuo)//设置a锁。
			{
				System.out.println("if....asuo");
				synchronized(MyLock.bsuo)//设置b锁。
				{
					System.out.println("if....bsuo");
				}
			}
		}
		else
		{
			synchronized(MyLock.bsuo)//设置b锁。
			{
				System.out.println("else!!!bsuo");
				synchronized(MyLock.asuo)//设置a锁。
				{
					System.out.println("else!!!asuo");
				}
			}
		}
	}
}


class MyLock
{
	static Object asuo =new Object();//创建两个不同的锁,为了方便调用,用static修饰。
	static Object bsuo =new Object();
}




class DeadLockTest
{
	public static void main(String[] args)
	{
		Thread t1=new Thread(new XianCheng(true));
		Thread t2=new Thread(new XianCheng(false));
		t1.start();
		t2.start();
	}
}

线程间的通讯:就是多个线程操作同一资源,但操作的动作不同。
如:
class ZiYuan
{
	String name;
	String sex;
}


class Input implements Runnable 
{
	private ZiYuan r;//建立引用变量和类的构造函数,让该类一初始化就有对应的ZiYuan对象,而且该ZiYuan对象与Output类操作
	Input(ZiYuan r)  // 的对象是同一个。
	{
		this.r=r;
	}


	public void run()
	{
		int x=0;
		while(true)
		{
			synchronized(r)//同步避免了输入与输出不符的情况。
			{
				if(x==0)
				{
					r.name="iron man";
					r.sex="male";
				}
				else
				{
					r.name="朴信惠";
					r.sex="女";
				}
			}
			x=(x+1)%2;//每进行一次输入操作,改变x的值。
			
		}
	}
}


class Output implements Runnable
{
	private ZiYuan r;
	Output(ZiYuan r)
	{
		this.r=r;
	}


	public void run()
	{
		while(true)
		{
			
			synchronized(r)//因为两线程需要同一个锁,而r又是唯一对象,所以用r锁。
			{
				System.out.println(r.name+"====="+r.sex);
			}
		}
	}
}


class TongXun01
{
	public static void main(String[] args)
	{
		ZiYuan r =new ZiYuan();
		Input in = new Input(r);
		Output out = new Output(r);
		Thread t1=new Thread(in);
		Thread t2=new Thread(out);
		t1.start();
		t2.start();
	}
}

等待唤醒机制:
wait();notify();notifyAll();都使用在同步中,因为要对持有监视器(锁)的线程操作,
所以要使用在同步中,因为只有同步才有锁,等待和唤醒必须是同一个锁。

JDK1.5中提供了多线程升级解决方案:
将同步synchronized替换成实现Lock操作。
将Object中的wait,notify,notifyAll替换成Condition对象,该对象可以通过Lock锁进行获取。

以上代码利用JDK1.5的方案后可优化为:
import java.util.concurrent.locks.*;


class ZiYuan
{
	private String name;
	private String sex;
	private boolean flag;
	private Lock lock = new ReentrantLock();//创建锁的对象。
	private Condition c = lock.newCondition();//获取Condition对象,因为要调用Condition里的方法。


	public  void set(String name,String sex)throws InterruptedException
	{
		lock.lock();
		try
		{
			while(flag)
				c.await();
			this.name=name;
			this.sex=sex;
			this.flag=true;
			c.signalAll();
		}
		finally
		{
			lock.unlock();
		}
	}


	public void ShuChu()throws InterruptedException
	{
		lock.lock();
		try
		{
			while(!flag)
				c.await();
			System.out.println(name+"====="+sex);
			this.flag=false;
			c.signalAll();
		}
		finally
		{
			lock.unlock();
		}
	}
}


class Input implements Runnable 
{
	private ZiYuan r;
	Input(ZiYuan r)  
	{
		this.r=r;
	}


	public void run()
	{
		int x=0;
		try
		{
			while(true)
			{
				if(x==0)
					r.set("iron man","male");
				else
					r.set("朴信惠","女");
			x=(x+1)%2;
			}
		}
		catch(InterruptedException e){ }
	}
}


class Output implements Runnable
{
	private ZiYuan r;
	Output(ZiYuan r)
	{
		this.r=r;
	}


	public void run()
	{
		try
		{
			while(true)
			{
				r.ShuChu();
			}
		}
		catch(InterruptedException e){ }
	}
}


class TongXun03
{
	public static void main(String[] args)
	{
		ZiYuan r =new ZiYuan();
		new Thread(new Input(r)).start();
		new Thread(new Output(r)).start();
		
	}
}

停止线程:
1,定义循环结束标记;
因为线程运行代码一般都是循环,只要控制了循环即可。
2,使用interrupt(中断)方法;
该方法是结束线程冻结状态,使线程回到运行状态中。
注意:stop方法已经过时,不再使用。
另外与线程相关的几个方法:
1、join方法
        当A线程执行到了b线程的.join()方法时,A线程就会等待,等B线程都执行完,A线程才会执行。(此时B和其他线程交替运行。)join可以用来临时加入线程执行。
2、setPriority()方法用来设置优先级
        MAX_PRIORITY 最高优先级10
        MIN_PRIORITY   最低优先级1
        NORM_PRIORITY 分配给线程的默认优先级
3、yield()方法可以暂停当前线程,让其他线程执行。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值