java基础--多线程


一、多线程的概述

进程:是一个正在执行中的程序。

           每个进程执行都至少有一个执行路径,或者叫一个控制单元。

线程:就是进程中的一个独立的控制单元。

JVM启动的时候会有一个进程java.exe。该进程中至少一个线程负现java程序的执行,

而且这个线程运行的代码在于main方法中,该线程称之为主线程。

扩展:其实更细节说明jvm,jvm启动不止一个线程,还有负责垃圾回机制的线程。

二、创建线程-继承Thread类

如何在自定义的代码中,自定义一个线程呢?

线程的创建可通过调用操作系统进行创建。java已经提供了对这类事物的描述,就是Thread类。

创建线程的第一种方式:继承Thread类

1、定义类继承Thread

2、复写Thread类中的run方法

3、调用线程的start方法,该方法两个作用:启动线程,调run方法

class OneThread extends Thread
{
	public void run()
	{
		for(int i = 0;i <60;i++)
		{
			System.out.println("i = " + i);
		}
	}
}
public class ThreadDemo {
	public static void main(String[] args)
	{
		OneThread oneThread = new OneThread();//创建一个线程
		oneThread.start();//使该线程开始执行;java虚拟机调用该线程的run方法
		for(int x = 0;x <60;x++)
		{
			System.out.println("x = " + x);
		}		
	}
}
上述程序中,oneThread.stat();代码执行后oneThread线程开始执行。这时,上述程序

就有两个线程在同时执行,主线程main和oneThread。两个线程在抢占cpu的执行权,

执行顺序也是随机。每一次运行结果无法确定的。


三、创建线程-run和start特点

run方法是用于储存线程要运行的代码。

start方法启动已创建的线程,并执行run方法

注意:直接调用run方法,程序不会启动相应的线程。下例代码只有main线程在执

行,执行结果,是run方法执行完毕后,再执行main方法中的for循环

		OneThread oneThread = new OneThread();//创建一个线程
		oneThread.run();   //对象调用run方法,线程未启动
		for(int x = 0;x <60;x++)
		{
			System.out.println("x = " + x);
		}		
四、线程的状态
线程都会经历从被创建到消亡的过程。线程从被创建后,在各个状态中的转换如下图所示:


五、获取线程的对象及名称

java中的线程都有自己的默认名称,主线程名称是main,其它线程的默名称是

Thread-编号 该编号从0开始。当然也可以自行设置线程的名称

class OneThread extends Thread
{
	OneThread()
	{
	}
	//通过构造方法设置线程名称
	OneThread(String name)
	{
		super(name);
	}
	public void run()
	{
		for(int i = 0;i <60;i++)
		{
			/*Thread.currentThread(),获取当前线程寻象的引用
			 * getName(),获取当前线程的名称
			 */
			System.out.println(Thread.currentThread().getName() + 
						" running " + "i = " + i);			
		}
	}
}
public class ThreadDemo {
	public static void main(String[] args)
	{
		OneThread oneThread = new OneThread();//创建一个线程,线程默认名称为Thread-0
		OneThread twoThread = new OneThread("线程二");//创建一个线程,并设置线程名称	
		oneThread.start();//使该线程开始执行;java虚拟机调用该线程的run方法
		twoThread.start();
		for(int x = 0;x <60;x++)
		{
			//主线程的名称默认为main
			System.out.println(Thread.currentThread().getName() + " running "+
					   "x = " + x);			
		}		
	}
}
六、售票的例子
下例程序是售卖票程序,可多个窗口同时卖。通过继承Thread类实现多线程的方式实现

/*
 * 需求:售卖票,可多个窗口同时卖。
 */
class Tick	extends Thread
{	//共享这100张票,必须设置成static
	private static int tick = 100;
	public void run()
	{
		while(tick > 0)
		{
			System.out.println(Thread.currentThread().getName() + " sale " +tick--);
		}
	}
}
public class TickDome {
	public static void main(String[] args )
	{    //四个窗口同时卖票,创建四个线程
		Thread t1 = new Tick();
		Thread t2 = new Tick();
		Thread t3 = new Tick();
		Thread t4 = new Tick();	
		t1.start();
		t2.start();
		t3.start();
		t4.start();		
	}
}

七、实现Runnable接口

创建线程的第二种方式:实现Runnable接口

步骤:

1、定认类实现Runnable接口

2、覆盖Runnable接口中的run方法,将线程要运行的中的run方法中

3、通过Thread类建立线程对象

4、将Runnable接口的子类对象作为实际参数传递给Thread类的构造方法。

      为什么要将Runnable接口的子类对象传递给Thread的构造方法?

      因为,自定义的run对象是Runnable接口的子类对象,所以要让线程去

      执行指定对象的run方法,就必须明确该run方法所属对象。

实现方式和继承方式有什么不区别呢?

由于javaj是单继承,所以一旦继承了Thread类,就不能再继承其它类。

实现的方式就避免了单继承的局限性,开发中常使用实现方式。

/*
 * 售卖票,可多个窗口同时卖的Runable实现方式
 */
class RTick implements Runnable
{  //多个线程共用一个对象无需定认为静态
	private  int tick = 100;
	public void run()
	{
		while(tick > 0)
		{
			System.out.println(Thread.currentThread().getName() + " sale " +tick--);
		}
	}	
}
public class RTickDome {
	public static void main(String[] args)
	{
		RTick rt = new RTick();
		Thread t1 = new Thread(rt);
		Thread t2 = new Thread(rt);
		Thread t3 = new Thread(rt);
		Thread t4 = new Thread(rt);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();			
	}
}
八、多线程的安全问题及同步代码块
当程序是多线程的,那么就有可能产生某一线程代码块运行未完成,便被其它线程打断

的问题,这有可能导致程序运行出错。

出错的一个原因:

      当多条语句操作同一个线程共享数据时,一个线程对多条语句只执行了一部,还没执行

      完,另一个线程参与进来执行,导致共享数据的错误。

解决办法:

      对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其它线程不可

      以参与执行

java提供了相应的解决方式,就是同步代码块:

  • synchronized(对象)    
  • {
  •         需要被同步的代码
  • }

synchronized里的对象如同锁,持有锁的线程可以在同步中执行。

没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。

改进原来的售票程序,如下:

<pre name="code" class="java">class RTick implements Runnable
{  //多个线程共用一个对象无需定认为静态
	private  int tick = 10000;
	Object obj = new Object();
	public void run()
	{
		while(true)
		{
			//这时的obj对象起开关作用,就像一个锁
			synchronized (obj) {
				if(tick > 0)
				{
					System.out.println(Thread.currentThread().getName() + " sale " +tick--);
				}	
				else
					break;
			}			
		}
	}	
}
 

九、同步方法

我们知道了可以通过同步代码块,对方法内的多条语句加同步锁。那么当我们需要

对方法内的所有语句都进行加同步锁时,可以采用另一种更好的书写方式,叫同步

方法。写书方式很简单,只需使用synchronized关键字修饰即可。

/*
 * 需求:银行有一个小金库。
 * 有两个储户分别存300元,每次存100,存3次
 */
/*
 * 为了防止多线程的运行代码被中断,必须给相关代语句加锁。
 * 线程语句中操作共享成员变量的语句不可被中断,加同步锁
 */

class Bank
{
	private int sum;

	//add方法内的所有语句共同操作共享成员变量sum。
	//用synchronized关键字修饰方法,add方法为同步方法
	public synchronized void add(int n)
	{
		sum = sum + n;
		System.out.println("sum = " + sum);			
	}
}
class Cus implements Runnable
{
	private Bank b = new Bank();
	public void run()
	{
		for(int x = 0; x<3; x++)
		{
			b.add(100);
		}
	}
}
public class BankDemo {
	public static void main(String[] args)
	{
		Cus c = new Cus();
		Thread t1 = new Thread(c);
		Thread t2 = new Thread(c);
		t1.start();
		t2.start();
	}
}

十、同步方法的锁是this

同步方法用的是哪一个锁呢?

方法需要被对象调用。方法都有一个所属对象的引用,就是this,同步方法使用的锁就是this

接下来验证一下这个结论。

验证前必须明确同步的前提:1、必须有两个或者两个以上的线程。2、必须是多个线程使用同一个锁。

若前提(2)不满足,锁无效,基于这一点用如下程序验证:

/*
 * 售卖票,两个窗口同时卖票,用于验证同步方法的锁是否为this
 * 一个卖票程序位于同步代码块中,一个位于同步方法中,只有用
 * 同一个锁才能保证程序不出错
 */
class LTick implements Runnable
{  //多个线程共用一个对象无需定义为静态
	private  int tick = 1000;
	boolean	flag =true;
//	Object obj = new Object();
	public void run()
	{
		if(flag)
		{
			while(true)
			{
				synchronized (this)   //使用this程序运行正常,表示与同步方法使用的锁也是this
				{
					if(tick > 0)
					{
						try{Thread.sleep(10);}catch(Exception e){}
						System.out.println(Thread.currentThread().getName() + " sale " +tick--);
					}			
				 else
						break;
				}	
			}
		}
		else
			while(true)
				{
				if(tick <= 0)	
					break;
				saleTick();				
				}
	}	
	synchronized void saleTick()
	{
		if(tick > 0)
			try{Thread.sleep(10);}catch(Exception e){}
			System.out.println(Thread.currentThread().getName() + " saleTick " +tick--);
	}
}
public class LockThisDemo {
	public static void main(String[] args)
	{
		LTick rt = new LTick();
		Thread t1 = new Thread(rt);
		Thread t2 = new Thread(rt);	
		t1.start();
		try{Thread.sleep(10);}catch(Exception e){}
		rt.flag = false;
		t2.start();		
	}
}
十一、静态同步方法的锁是Class对象

如果同步方法被静态修饰后,使用的锁是什么呢?

可通过验证,发现是this。因为静态方法中也不可以定义this。

静态的进内存是,内存中没有本类对象,但是一定有该类对应的字节码对象文件——类名.Class

class LTick implements Runnable
{       //定义为静态成员
	private  static int tick = 1000;
	boolean	flag =true;
	public void run()
	{
		if(flag)
		{
			while(true)
			{
				synchronized (LTick.class)   //Class类型的对象
				{
					if(tick > 0)
					{
						try{Thread.sleep(10);}catch(Exception e){}
						System.out.println(Thread.currentThread().getName() + " sale " +tick--);
					}			
				 else
						break;
				}	
			}
		}
		else
			while(true)
				{
				if(tick <= 0)	
					break;
				saleTick();				
				}
	}	
	static synchronized void saleTick()  //静态同步方法
	{
		if(tick > 0)
			try{Thread.sleep(10);}catch(Exception e){}
			System.out.println(Thread.currentThread().getName() + " saleTick " +tick--);
	}
}
十一、多线程-单例设计模式-懒汉式

在前面我们个绍过懒汉式的单例设计模式,这个模式存在技术风险。知道了多线程中的

锁,我们就可以来解决这个问题了。因为在getInstance()方法中有多条语句操作生成共

享成员变量(LSingle对象),所以存在被多个线程同时调用时,程序被中断而可能出现

程序运行结果不正确的风险。只需用同步方法即可解决,但是每次调用getInstance()都

要判断锁,会降低性能,因此,我们采用同步代代码块进行解决,见示例代码:

class LSingle
{
	private static LSingle s = null;
	private LSingle(){};
	public static LSingle getInstance() {
		if(s == null)
		{
			synchronized(LSingle.class)
			{
				if(s==null) 
					s = new LSingle();	
			}			
		}
		return s;
	}
}	
十二、多线程-死锁
什么是死锁呢?考虑一下这样的情景,有两个人要吃饭,桌上有一双筷子各自拿了一根

筷子,互不让,这样两人都无法吃饭。类似的程序中也有可能出现这样一种情况,有两

个线程,每个线程代码都同时需要两个锁,才能正常运行。各自拿了一个锁,导致两线

程都无法正常运行。

//测试死锁程序
class TestLock implements Runnable
{
	 boolean flag = false;
	TestLock(boolean flag)
	{
		this.flag = flag;
	}
	public void run()
	{
		if(this.flag == true)
		{	//同步嵌套,可能会死锁
			synchronized(MyLock.la)
			{
				System.out.println("if locka");
				synchronized(MyLock.lb)
				{
					System.out.println("if lockb");
				}
			}
		}
		else
		{   //同步嵌套,可能会死锁
			synchronized(MyLock.lb)
			{
				System.out.println("else lockb");
				synchronized(MyLock.la)
				{
					System.out.println("else locka");
				}
			}
		}
	}
}
class MyLock
{
	//两个同步用的锁
	static Object la = new Object();
	static Object lb = new Object();
}
public class TestLockDemo {
	public static void main(String[] args)
	{
		Thread t1 =new Thread(new TestLock(true));
		Thread t2 =new Thread(new TestLock(false));		
		t1.start();
		t2.start();
	}
}
十三、多线程的通信-wait()、notify()、notifyAll()

一个程序中的多个线程可能需要对同一资源进行操作,且不同的线程的功能不同,这样

线程之间就需要协作,协作就需要进行通信。在同步方法和语句中常见的通信操作有定

义在Object中的wait()、notify()、notifyAll()。注意,wait()方法的执行会释放synchronized

中的锁。下面的例子演示的这种用法:

/*
 * 线程通信。Input线程与Output线程操作同一个资源
 * 存一个信息就打印一个信息
 */

class Res
{
	String name;
	String sex;
	boolean flag = false;
}

//往资源里面存入信息
class Input implements Runnable
{
	private Res r;
	Input(Res r)
	{
		this.r = r;
	}
	public void run()
	{
		int x = 0;
		while(true)
		{
			synchronized(Res.class)
			{
				if(r.flag)
				{
					try
					{
						Res.class.wait(); //执行wait()会释放锁
					}
					catch(Exception e)
					{
					}
				}
				if(x == 0)
				{
					r.name = "mike";
					r.sex = "man";
				}
				else
				{
					r.name = "丽丽";
					r.sex = "女女女女";				
				}
				x = (x +1) % 2;
				r.flag = true;				
				Res.class.notify();
			}
		}
	}
}
//打印资源里面信息
class Output implements Runnable
{
	private Res r;
	Output(Res r)
	{
		this.r = r;
	}
	public void run()
	{
		while(true)
			synchronized(Res.class)
			{
				if(!r.flag)
				{
					try
					{
						Res.class.wait();
					}
					catch(Exception e)
					{
						
					}
					System.out.println(r.name +"----" + r.sex);		
				}
				r.flag = false;				
				Res.class.notify();
			}
	}
}
public class InOutDome {
	public static void main(String[] args)
	{
		Res r = new Res();
		Input in = new Input(r);
		Output out = new Output(r);
		Thread t1 = new Thread(in);
		Thread t2 = new Thread(out);
		t1.start();
		t2.start();
	}
}
输出如下:

mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
mike----man
丽丽----女女女女
可对上述的代码进行优化:
/*
 * 优化代码
 * 线程通信。Input线程与Output线程操作同一个资源
 * 存一个信息就打印一个信息
 */

class Res2
{
	private String name;
	private String sex;
	private boolean flag = false;
	
	synchronized void set(String name,String sex)
	{
		if(flag)
		{
			try
			{
				this.wait();
			}
			catch(Exception e)
			{			
			}
		}
		this.name = name;
		this.sex = sex;
		flag = true;
		this.notify();
	}
	synchronized void out()
	{
		try
		{
			if(!flag)
			{
				this.wait();
			}	
		}
		catch(Exception e)
		{		
		}
		System.out.println(this.name +"----" + this.sex);	
		this.flag = false;
		this.notify();		
	}
}

//往资源里面存入信息
class Input2 implements Runnable
{
	private Res2 r;
	Input2(Res2 r)
	{
		this.r = r;
	}
	public void run()
	{
		int x = 0;
		while(true)
		{
			if(x == 0)
			{
				r.set("mike","man");
			}
			else
			{
				r.set("丽丽---------","女女女女");								
			}
			x = (x +1) % 2;
		}
	}
}
//打印资源里面信息
class Output2 implements Runnable
{
	private Res2 r;
	Output2(Res2 r)
	{
		this.r = r;
	}
	public void run()
	{
		while(true)
			r.out();
	}
}
public class InOutDome2 {
	public static void main(String[] args)
	{
		Res2 r = new Res2();
		new Thread(new Input2(r)).start();
		new Thread(new Output2(r)).start();		
	}
}
在实际开发中,有一种与上述程序类似的模式,叫生产者消费者模式。生产一个

消费模式,多个线程生产,多个线程消费

/*
 * 生产者、消费者。两个线程生产,两个线程消费
 */
class Resource
{
	private String name;
	private int count = 1;
	private boolean flag = false;
	
	synchronized void set(String name)
	{
		/*之所以用while,不用if是因为某一线程执行了wait()后,被其它
		 * 线程唤醒后,会从wait()后开始执行,程序就没有判断flag,可
		 * 能引起错误,用while保证每次执行都会判断flag
		 */
		while(flag)  
		{
			try
			{
				wait(); //省略了this
			}
			catch(Exception e)
			{				
			}
		}
		this.name = name + count++;
		System.out.println(Thread.currentThread().getName() + "-----" + "生产者" +this.name);
		flag = true;
		notifyAll();  //唤醒全部线程
	}
	synchronized void out()
	{
		while(!flag)
		{
			try
			{
				wait(); //省略了this
			}
			catch(Exception e)
			{				
			}
		}
		System.out.println(Thread.currentThread().getName() + "----------------" + "消费者"+name);
		flag = false;
		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();
		}
	}
}
public class ProducerConsumerDemo 
{
	public static void main(String[] args)
	{
		Resource r = new Resource();
		Producer p = new Producer(r);
		Consumer con = new Consumer(r);
		Thread t1 =new Thread(p);
		Thread t2 =new Thread(p);		
		Thread t3 =new Thread(con);	
		Thread t4 =new Thread(con);			
		t1.start();
		t2.start();
		t3.start();
		t4.start();		
	}
}
十四、多线程的通信-Lock-Condition

在JDK1.5引进了Lock-Condition。Lock接口替代synchronized方法和语句的使用,

Condition接口替代了Object监初视器方法的使用。一个Lock支持邦定多个Condition

对象使用Condition实现了对特定的线程进行操作

/*
 * 该程序是生产者、消费者的Lock-Condition版。
 * 该示例实现了本方线程对对方线程的唤醒。
 */
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Lock;

class LResource
{
	private String name;
	private int count = 1;
	private boolean flag = false;
	private Lock  lock = new ReentrantLock(); //创建一个锁
	private Condition  conditionPro = lock.newCondition();//邦定到锁的Condition对象
	private Condition  conditionCon = lock.newCondition();	
	void set(String name) throws InterruptedException
	{
		lock.lock();		
		try
		{
			while(flag)  
			{
				conditionPro.await(); //生产者对应线程等待
			}
			this.name = name + count++;
			System.out.println(Thread.currentThread().getName() + "-----" + "生产者" +this.name);
			flag = true;
			conditionCon.signal();;  //唤醒消费者对应线程			
		}
		finally
		{
			lock.unlock();
		}
	}
	 void out() throws InterruptedException
	{
		 lock.lock();
		 try
		 {
			 	while(!flag)
				{
			 		conditionCon.await();//消费者对应线程等待
				}
				System.out.println(Thread.currentThread().getName() + "----------------" + "消费者"+name);
				flag = false;
				conditionPro.signal();	//唤醒生产者对应线程				 
		 }
		 finally
		 {
			 lock.unlock();
		 }
	}
}
class LProducer implements Runnable
{
	private LResource r;
	LProducer(LResource r)
	{
		this.r = r;
	}
	public void run()
	{
		while(true)
		{
			try
			{
				r.set("商品");				
			}
			catch(Exception e)
			{			
			}	
		}
	}
}
class LConsumer implements Runnable
{
	private LResource r;
	LConsumer(LResource r)
	{
		this.r = r;
	}
	public void run()
	{
		while(true)
		{
			try
			{
				r.out();				
			}
			catch(Exception e)
			{
			}
		}
	}
}
public class LProducerConsumerDemo 
{
	public static void main(String[] args)
	{
		LResource r = new LResource();
		LProducer p = new LProducer(r);
		LConsumer con = new LConsumer(r);
		Thread t1 =new Thread(p);
		Thread t2 =new Thread(p);		
		Thread t3 =new Thread(con);	
		Thread t4 =new Thread(con);			
		t1.start();
		t2.start();
		t3.start();
		t4.start();		
	}
}

十四、停止线程

Threadable类中有stop方法,但以过时。

如何停止线程?只有一种方式,run方法结束。

开启多线程运行,运行代码通常是循环结构。只要控制信循环,就可以让run方法结束,

也就线程结束。

//正常情况下停止线程
class StopThread implements Runnable
{
	private boolean flag = true;
	public void run()
	{
		while(flag)
		{
			System.out.println(Thread.currentThread().getName() + "----------run");
		}
	}
	void changeFlag()
	{
		flag = false;
	}
}

public 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 i = 0;		
		while(true)
		{
			if(i >=60)
			{
				st.changeFlag();
				break;
			}
			System.out.println(Thread.currentThread().getName() + "----main" + i++);
		}
	}
}
特殊情况:

当线程处于冻结状态,程序不会读取到标记,那么线程不会结束。那么可以使用Thread类

提供的interrupt()方法,强制线程恢复到运行状态中来,这样就可以操作标记让线程结束。

//停止处于冻结状态的线程
class StopThread2 implements Runnable
{
	private boolean flag = true;
	public synchronized void run()
	{
		while(flag)
		{
			try
			{
				wait();
			}
			//被interrupt方法强制清除冻结状态,wait()会抛出异常InterruptedException
			catch(InterruptedException e)
			{
				System.out.println(Thread.currentThread().getName() + "---Exception");
				flag = false;
			}
			System.out.println(Thread.currentThread().getName() + "----------run");
		}
	}
	void changeFlag()
	{
		flag = false;
	}
}

public class StopThreadDemo2 {
	public static void main(String[] args)
	{
		StopThread2 st = new StopThread2();
		Thread t1 = new Thread(st);
		Thread t2 = new Thread(st);
		t1.start();
		t2.start();
		int i = 0;		
		while(true)
		{
			if(i >=60)
			{
				//st.changeFlag();
				t1.interrupt();//强制清除t1线程的中断状态
				t2.interrupt();//强制清除t2线程的中断状态				
				break;
			}
			System.out.println(Thread.currentThread().getName() + "----main" + i++);
		}
		System.out.println("over");
	}
}
十五、守护线程
线程可分为用护线程和守护线程,当程序中只能守护线程时,jvm退出,即守护线程

结束。在线程的启动前可调用Thread的setDaemon()方法将线程标记为守护线程或

用户线程。

//主线程停止,守护线程随之停止
class StopThread implements Runnable
{
	//private boolean flag = true;
	public void run()
	{
		while(true)
		{
			System.out.println(Thread.currentThread().getName() + "----------run");
		}
	}
//	void changeFlag()
//	{
//		flag = false;
//	}
}

public 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 i = 0;		
		while(true)
		{
			if(i >=60)
			{
				//st.changeFlag();
				break;
			}
			System.out.println(Thread.currentThread().getName() + "----main" + i++);
		}
		System.out.println("over");
	}
}
主线程停止,守护线程随之停止

main----main53
main----main54
main----main55
main----main56
main----main57
main----main58
main----main59
over                          //主线程在这里停止了
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-1----------run
Thread-0----------run           //守护线程在这里停止了
十六、join方法
join方法:

当A线程执行到了B线程join方法时,A就会等待,等B线程执行完,A才会执行。、

join可以用来临时加入到线程执行

class JoinThread implements Runnable
{
	public void run()
	{
		for(int i = 0;i < 70;i++)
		{
			System.out.println(Thread.currentThread().getName() + "-run");
		}		
	}
}
public class JoinThreadDemo {
	public static void main(String[] args) throws InterruptedException
	{
		JoinThread jt = new JoinThread();
		Thread t1 = new Thread(jt);
		Thread t2 = new Thread(jt);
		t1.start();
		//t1.join(); 主线程停止,等t1线程执行完主线程才往下执行
		t2.start();
		t1.join();// 主线程停止,等t1线程执行完主线程才往下执行,t1和t2同时执行
		for(int i = 0;i < 70;i++)
		{
			System.out.println(Thread.currentThread().getName() + "-run");
		}			
		System.out.println("over");
	}
}
十七、优先级与yield方法
线程有优先级从1~10,默认是情况下是第5级。优先级越大抢到执行权的频率就越高。

优先级的大小可通过Thread类的setPriority方法设定优先级。

有时为了使程序的线程能尽可能的平均、交替的执行,可使用yield方法当前线程暂停一

下,将执行权让给其它线程。

class Yield implements Runnable
{
	public void run()
	{
		for(int i = 1;i <70;i++)
		{    //toString返回线程名称、优先级、线程组                                                                         
			System.out.println(Thread.currentThread().toString() + i);
			Thread.yield();			//暂停一下当前线程
		}
	}
}
class Priority implements Runnable
{
	public void run()
	{
		for(int i = 1;i <70;i++)
		{
			System.out.println(Thread.currentThread().toString() + i);
		}
	}
}
public class PriorityYieldDemo {
	public static void main(String[] args)
	{
		Yield y = new Yield();
		Priority p = new Priority();
		Thread t1 = new Thread(y);
		Thread t2 =new Thread(y);
		Thread t3 = new Thread(p);
		t1.start();
		t2.start();
		t3.setPriority(Thread.MAX_PRIORITY);//设置线程t3为最高优先级
		t3.start();
	}
}











































































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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值