首页 > 代码库 > 12-23java面向对象之多线程

12-23java面向对象之多线程

1.多线程的概念

几乎所有的操作系统都支持同时运行多个任务,每一个任务通常就是一个程序,每个运行的程序就是一个进程。当一个程序运行是,内部可能包含了多个顺序执行流,每个执行流就是线程。

继承的特点:并发性。多个进程可以在单个处理器上并发执行,不会相互影响,

2.java多线程的实现

2.1继承Thread

java.lang包中定义了Thread类,继承该类之后,必须覆写run()方法.

启动该线程,必须调用Thread类中的start()方法,但是该方法最终还是调用的run()方法。

class MyThread extends Thread		// 继承Thread类
{	
	private String name ;
	public MyThread(String name)	// 构造方法
	{
		this.name = name ;
	}
	public void run()				// 覆写run方法
	{
		for (int i =0;i<10 ;++i )
		{
			System.out.println(this.name + "运行,i=" + i);
		}
	}
}
public class TestThread1 
{
	public static void main(String[] args) 
	{
		MyThread mt1 = new MyThread("线程1") ;
		MyThread mt2 = new MyThread("线程2") ;
		mt1.run();
		mt2.run();
	}
}
技术分享
运行结果发现:并没有并发执行效果,所以要修改程序。必须使用start()方法来启动线程。

class MyThread extends Thread		// 继承Thread类
{	
	private String name ;
	public MyThread(String name)	// 构造方法
	{
		this.name = name ;
	}
	public void run()				// 覆写run方法
	{
		for (int i =0;i<10 ;++i )
		{
			System.out.println(this.name + "运行,i=" + i);
		}
	}
}
public class TestThread2 
{
	public static void main(String[] args) 
	{
		MyThread mt1 = new MyThread("线程1") ;		// 创建对象
		MyThread mt2 = new MyThread("线程2") ;
		mt1.start();
		mt2.start();
	}
}
技术分享

程序运行总是并发执行不同的线程。那个线程先抢占到CPU资源就执行它。

如果线程已经启用了,再次调用start方法会出现异常。

class MyThread extends Thread		// 继承Thread类
{	
	private String name ;
	public MyThread(String name)	// 构造方法
	{
		this.name = name ;
	}
	public void run()				// 覆写run方法
	{
		for (int i =0;i<10 ;++i )
		{
			System.out.println(this.name + "运行,i=" + i);
		}
	}
}
public class TestThread3 
{
	public static void main(String[] args) 
	{
		MyThread mt1 = new MyThread("线程1") ;		// 创建对象	
		mt1.start();
		mt1.start();
	}
}

提示错误信息;

Exception in thread "main" java.lang.IllegalThreadStateException

        at java.lang.Thread.start(Unknown Source)

        at TestThread3.main(TestThread3.java:22)

2.2实现Runnable接口

Runnable接口中只定义了run()方法,所以也需要覆写该方法。它之中并没有start()方法,但是在Thread的构造方法中有这么一个接收Runnable实例的,用他作为启动线程的操作。

Thread
public Thread(Runnable target)

class MyThread implements Runnable		// 继承Thread类
{	
	private String name ;
	public MyThread(String name)	// 构造方法
	{
		this.name = name ;
	}
	public void run()				// 覆写run方法
	{
		for (int i =0;i<10 ;++i )
		{
			System.out.println(this.name + "运行,i=" + i);
		}
	}
}
public class TestThread4 
{
	public static void main(String[] args) 
	{
		Runnable r1 = new MyThread("线程1") ;		// 向上转换实现接口	
		Runnable r2 = new MyThread("线程2") ;		// 向上转换实现接口	
		Thread mt1 = new Thread(r1);
		Thread mt2 = new Thread(r2);
		mt1.start();
		mt2.start();
	}
}

执行结果:完成了多线程的功能。

技术分享

2.3联系与区别

联系:定一个是Thread也是Runnable的实现,这个就是之前的代理设计。

技术分享

All Implemented Interfaces:   Runnable

区别:使用Thread操作多线程无法实现资源的共享,而Runnable可以共享。同时Thread只能实现单继承,接口可以多继承,推荐使用Runnable

使用Runnable优点:

1、适合多个相同程序代码的多线程处理同一个资源

2、避免单继承

3、增强健壮性

下面验证共享;

//本程序验证共享属性
class MyThread extends Thread		
{	
	private int ticket = 5;			// 定义属性有5个
	public void run()				// 覆写run方法
	{
		for (int i =0;i<10 ;++i )
		{
			if (ticket > 0)
			{
				System.out.println("卖出门票ticket =" + ticket--);
			}			
		}
	}
}
public class TestThread6
{
	public static void main(String[] args) 
	{
		Thread mt1 = new MyThread();		
		Thread mt2 = new MyThread();
		mt1.start();
		mt2.start();
	}
}
技术分享

这个时候发现,每个线程都各卖个的,没有到达资源共享。

//本程序验证共享属性
class MyThread implements Runnable		// 实现Runnable接口
{	
	private int ticket = 5;			// 定义属性有5个
	public void run()				// 覆写run方法
	{
		for (int i =0;i<10 ;++i )
		{
			if (ticket > 0)
			{
				System.out.println("卖出门票ticket =" + ticket--);
			}			
		}
	}
}
public class TestThread5 
{
	public static void main(String[] args) 
	{
		Runnable r1 = new MyThread() ;		// 向上转换实现接口	
		Thread mt1 = new Thread(r1);		
		Thread mt2 = new Thread(r1);
		mt1.start();
		mt2.start();
	}
}
技术分享

3.线程的状态

 

调用了start也不会立即启动,需要等待CPU

4.线程的操作方法

对线程的操作都在Thread类中。

 

4.1取得和设置线程名称

Thread类的构造方法中有一个名称的参数,同时具有方法setName()getName()可以分别设置和获取名称。线程名称可以相同,在运行时候可以修改。

Public static Thead currentThread()方法返回当前的线程。

//本程序测试线程名称
class MyThread implements Runnable
{	
	public void run()				// 覆写run方法
	{
		for (int i =0;i<10 ;++i )
		{
			System.out.println(Thread.currentThread().getName() +"当前线程名称是—"+ i);
		}
	}
}
public class TestThread7
{
	public static void main(String[] args) 
	{
		Runnable mt1 = new MyThread();		
		Runnable mt2 = new MyThread();
		Thread t1 = new Thread(mt1);			//系统自动命名
		Thread t2 = new Thread(mt2,"线程A");			//手动命名
		t1.start() ;
		t2.start();	
	}
}

技术分享

运行发现,线程设置名称之后会按照设置名称自动运行,没有设置名称的按照格式Thread-0 依次编号,实际上肯定存在static属性,用于记录产生对象的个数。

4.2取得当前线程

public static Thread currentThread()

Returns a reference to the currently executing thread object.

//本程序测试线程名称
class MyThread implements Runnable
{	
	public void run()				// 覆写run方法
	{
		for (int i =0;i<10 ;++i )
		{
			System.out.println(Thread.currentThread().getName() +"当前线程名称是—"+ i);
		}
	}
}
public class TestThread8
{
	public static void main(String[] args) 
	{
		Runnable mt2 = new MyThread();
		Thread t2 = new Thread(mt2,"线程A");			//手动命名
		t2.start();
		t2.run();	
	}
}

此时程序中由主方法直接调用线程的run方法,此时main是由“t2.run();”产生的。

技术分享

Java程序在启动的时候至少有两个线程。JVM运行的时候启动了一个线程,在资源管理器中能够看到,同时后台还有垃圾收集GC线程。

4.3判断线程是否在执行

public final boolean isAlive()
//本程序测试线程名称
class MyThread implements Runnable
{	
	public void run()				// 覆写run方法
	{
		for (int i =0;i<3 ;++i )
		{
			System.out.println("当前线程名称是—"+Thread.currentThread().getName() + i);
		}
	}
}
public class TestThread9
{
	public static void main(String[] args) 
	{
		Runnable mt2 = new MyThread();
		Thread t2 = new Thread(mt2,"线程A");			//手动命名
		System.out.println("线程启动之前->" + t2.isAlive());
		t2.start();
		System.out.println("线程启动之后->" + t2.isAlive());
		for (int i= 1;i<10 ;++i )
		{
			System.out.println(t2.isAlive());
		}
		System.out.println("代码执行之后->" + t2.isAlive());
	}
}

由于此时在线程A和主方法中执行次序不确定,所以结果不同。

4.4线程强制运行

public final void join()                throws InterruptedException

Waits for this thread to die.

//本程序测试线程名称
class MyThread implements Runnable
{	
	public void run()				// 覆写run方法
	{
		for (int i =0;i<40 ;++i )
		{
			System.out.println("当前线程名称是—"+ Thread.currentThread().getName() + i);
		}
	}
}
public class TestThread10
{
	public static void main(String[] args) 
	{
		Runnable mt1 = new MyThread();
		Thread t1 = new Thread(mt1,"线程A");			//手动命名
		t1.start();
		for (int i =0;i<40 ;++i )
		{
			if (i>10)
			{
				try
				{
					t1.join();
				}
				catch (InterruptedException e)
				{
				}
			}
			System.out.println("main运行" + i);
		}
	}
}

技术分享

main运行到10之后,都是由主线程占用。

4.5线程的休眠

public static void sleep(long millis)  使用类名称调用,类似current                  throws InterruptedException

//本程序测试线程名称
class MyThread implements Runnable
{	
	public void run()				// 覆写run方法
	{
		for (int i =0;i<10 ;++i )
		{
			try
			{
				Thread.sleep(2000);			// 每2s产生一个输出
			}
			catch (InterruptedException e)
			{
			}
			System.out.println("当前线程名称是—"+ Thread.currentThread().getName() + i);
		}
	}
}
public class TestThread11
{
	public static void main(String[] args) 
	{
		Runnable mt1 = new MyThread();
		Thread t1 = new Thread(mt1,"线程A");			//手动命名
		t1.start();
	}
}

4.6线程强制中断

当一个线程正在运行时,另一个线程可以使用interrupt方法中断其运行。

public void interrupt()

Interrupts this thread.

//本程序测试线程名称
class MyThread implements Runnable
{	
	public void run()				// 覆写run方法
	{
		System.out.println("1.进入run方法");
		try
		{
			Thread.sleep(5000);			// 休眠5s
			System.out.println("2.休眠结束");
		}
		catch (InterruptedException e)
		{
			System.out.println("3.休眠中断");
			return ;		// 返回调用处
		}
		System.out.println("4.run正常结束");
	}
}
public class TestThread12
{
	public static void main(String[] args) 
	{
		Runnable mt1 = new MyThread();
		Thread t1 = new Thread(mt1,"线程A");			//手动命名
		t1.start();
		try  //作用是延时
		{
			Thread.sleep(2000);			
		}
		catch (InterruptedException e)
		{}
		t1.interrupt();
	}
}
技术分享

4.7后台线程

一个线程在运行,整个java进程不会消失。可以设置后台线程,哪怕进程结束了,线程还在。

public final void setDaemon(boolean on)

class MyThread implements Runnable
{	
	public void run()				// 覆写run方法
	{
		while (true)
		{
			System.out.println(Thread.currentThread().getName() + "在运行");
		}
	}
}
public class TestThread13
{
	public static void main(String[] args) 
	{
		Runnable mt1 = new MyThread();
		Thread t1 = new Thread(mt1,"线程A");			//手动命名
		t1.start();
		t1.setDaemon(true);
	}
}

4.8优先级设置

public final void setPriority(int newPriority)

Changes the priority of this thread.

<p>注意:主方法的优先级是<span style="font-family:Times New Roman;">5</span></p><h2>4.9<span style="font-family:黑体;">线程的礼让</span></h2><table><tbody><tr><td valign="top"><p>public static void yield()</p><p>Causes the currently executing thread object to temporarily pause and allow other threads to execute.</p></td></tr></tbody></table>class MyThread implements Runnable
{	
	public void run()				// 覆写run方法
	{
		for (int i=0;i<3 ;++i )
		{
			try
			{
				Thread.sleep(1000);			
				System.out.println("正在运行的是: " + Thread.currentThread().getName() + i);
			}
		catch (InterruptedException e){}
		}
	}
}
public class TestThread14
{
	public static void main(String[] args) 
	{
		Runnable mt1 = new MyThread();
		Thread t1 = new Thread(mt1,"线程A");			//手动命名
		Runnable mt2 = new MyThread();
		Thread t2 = new Thread(mt2,"线程B");			//手动命名
		Runnable mt3 = new MyThread();
		Thread t3 = new Thread(mt3,"线程C");			//手动命名
		t1.setPriority(Thread.MAX_PRIORITY);							//设置优先级
		t2.setPriority(Thread.MIN_PRIORITY);
		t3.setPriority(Thread.NORM_PRIORITY);
		t1.start();
		t2.start();
		t3.start();
	}
}

注意:主方法的优先级是5

4.9线程的礼让

public static void yield()

Causes the currently executing thread object to temporarily pause and allow other threads to execute.

class MyThread implements Runnable
{	
	public void run()				// 覆写run方法
	{
		for (int i=0;i<5 ;++i )
		{
			System.out.println("正在运行的是: " + Thread.currentThread().getName() + i);
			if (i ==3)
			{
				System.out.println("线程礼让");
				Thread.currentThread().yield();
			}
		}
	}
}
public class TestThread15
{
	public static void main(String[] args) 
	{
		Runnable mt1 = new MyThread();
		Thread t1 = new Thread(mt1,"线程A");			//手动命名
		Runnable mt2 = new MyThread();
		Thread t2 = new Thread(mt2,"线程B");			//手动命名
		t1.start();
		t2.start();
	}
}
技术分享

祝大家健健康康,快快乐乐。


12-23java面向对象之多线程