JAVA学习第二十三课(多线程(二))- (多线程的创建方式二 :实现Runnable接口(常用))

当一个类有父亲,但是其中的功能还希望实现线程,那么就不能采用继承Thread的方式创建线程

那么就可以通过接口的方式完成

准备扩展Demo类的功能,让其中的内容可以作为线程的任务执行

实现Runnable接口,Runnable接口中只有一个方法run

一、创建线程的第二种方法

Runnable的出现仅仅是将线程的任务进行了对象的封装

/*

* 创建线程的第二种方法

* 1.定义类实现Runnable接口

* 2.覆盖接口中的fun方法,将线程的任务代码封装到run方法中

* 3.通过Thread类创建线程对象,并将Runnable接口的子类对象作为构造函数的参数进行传递

* 为什么?因为线程的任务都封装在Runnable接口子类对象的run方法中,所以要在线程对象创建

* 时就要明确要运行的任务

* 4.调用线程的start方法开启线程

 */

class Demo implements Runnable
{
	public void run()
	{
		show();
	}
	public void show()
	{
		for(int i = 0;i<10;i++)
		{
			System.out.println(Thread.currentThread().getName()+"i = "+i);
		}
	}
}
public class Main
{
	public static void main(String[] args)
	{
		//定义线程的方式
		Demo jo = new Demo();
		//Thread中有一个Thread(Runnable t)的方法
		Thread aThread = new Thread(jo);
		//如果不传递,start只会执行自己的方法
		Thread bThread = new Thread(jo);
		aThread.start();
		bThread.start();
	}
}

二、实现Runnable接口和继承Thread类的区别

实现Runnable接口的好处:

1.将线程的任务同线程的子类中分离出来,进行了单独的封装,也就是将任务封装成了对象

2.避免了单继承的局限性

所以,创建线程的第二种方式较为常用。

三、代码实例:

第一种线程的创建方式

/*
 * 需求:4个窗口进行买票,票数100张,编号1-100
 *
 */
class Ticket extends Thread
{
	private int num = 100;
	//private static int num = 100;
	public void run()
	{
		while(true)
		{
			if(num>0)
			{
				System.out.println(Thread.currentThread().getName()+"..sale.."+num--);
			}
		}
	}
}
public class Main
{
	public static void main(String[] args)
	{
		Ticket j1 = new Ticket();
		Ticket j2 = new Ticket();
		Ticket j3 = new Ticket();
		Ticket j4 = new Ticket();
		j1.start(); j2.start();
		j3.start(); j4.start();
	}
}

PS:用第一种方式创建线程,可能出现有多个窗口卖同一号票的情况(1号窗口卖10号票,3号窗口也卖10号票)当然可以将票定义为静态的,但是仅限于是一种票,如果多种票就不适用了

第二种创建线程的方式

/*
 * 需求:4个窗口进行买票,票数100张,编号1-100
 *
 */
class Ticket implements Runnable
{
	private int num = 100;
	//private static int num = 100;
	public void run()
	{
		while(true)
		{
			if(num>0)
			{
				System.out.println(Thread.currentThread().getName()+"..sale.."+num--);
			}
		}
	}
}
public class Main
{
	public static void main(String[] args)
	{
		/*
		Ticket t = new Ticket();//将 卖票这一行为封装成对象
		Thread j1 = new Thread(t);
		Thread j2 = new Thread(t);
		Thread j3 = new Thread(t);
		Thread j4 = new Thread(t);
		j1.start(); j2.start();
		j3.start(); j4.start();
		*/
		//两种票,站票、坐票
		Ticket zhanpiao = new Ticket();
		Ticket zuopiao = new Ticket();
		//1 2窗口卖站票,3 4 窗口卖坐票
		Thread j1 = new Thread(zhanpiao);
		Thread j2 = new Thread(zhanpiao);
		Thread j3 = new Thread(zuopiao);
		Thread j4 = new Thread(zuopiao);
		j1.start(); j2.start();
		j3.start(); j4.start();
	}
}

四、线程的安全问题

public void run()
	{
		while(true)
		{
			if(num>0)
			{
				System.out.println(Thread.currentThread().getName()+"..sale.."+num--);
			}
		}
	}

这段代码是存在安全隐患的,理想状态下不会出现卖0号票的可能,但是一旦出现,进程就会出事

class Ticket implements Runnable
{
	private int num = 100;
	//private static int num = 100;
	public void run()//此处不能throws,因为Runnable没有声明异常
	{
		while(true)
		{
			if(num>0)
			{
				//睡10毫秒,sleep可能存在异常
				//所以只能try,catch,不能抛
				try
				{
					Thread.sleep(10);
				}
				catch (InterruptedException e)
				{
					// TODO: handle exception
				}

				System.out.println(Thread.currentThread().getName()+"..sale.."+num--);
			}
		}
	}
}
public class Main
{
	public static void main(String[] args)
	{
		Ticket t = new Ticket();
		Thread j1 = new Thread(t);
		Thread j2 = new Thread(t);
		Thread j3 = new Thread(t);
		Thread j4 = new Thread(t);
		j1.start(); j2.start();
		j3.start(); j4.start();

	}
}

这就出现了安全隐患,所以在写多线程时,必须考虑安全问题

五、线程安全问题产生的原因:

1.多个线程在操作共享的数据(4个窗口操作共享的num)

2.操作共享数据的线程代码有多条

当一个线程在执行操作共享数据的多条代码过程中,其他线程参与运算,就会导致线程安全问题的产生

(举个简单的例子就是,1号窗口在卖1号票的时,还没卖完,2号窗口就把1号票卖完了,这就会出现卖0号票的情况,如果不try。。直接卖一般不会出事)

时间: 2024-10-11 12:19:00

JAVA学习第二十三课(多线程(二))- (多线程的创建方式二 :实现Runnable接口(常用))的相关文章

JAVA学习第二十一课(多线程(一)初步了解)

放假在家,歇了好几天了,也没学习,今天学习一下多线程,找找感觉,后天就要回学校了,sad... PS:包 没有什么技术含量,会用即可,日后开发就必须要会用啦,所以打算先放一放,先来多线程 一.多线程概述 什么是进程? 通俗的说,可以理解为正在进行中的程序,进程实际上是对应的一个应用程序在内存中所属空间. 进程不直接执行的,进程只是分配该应用程序需要的内存空间,线程来负责执行,线程负责进程中内容执行的一个控制单元,也称之为执行路径,也称之为执行情景 什么是线程? 线程就是进程中一个负责程序执行的控

JAVA学习第二十课(异常的应用和注意事项(三))

十.异常的应用 import java.util.Random; import javax.rmi.CORBA.Stub; /* *老师用电脑上课 *用面向对象思考问题 *问题设计两个对象 *老师,电脑 * *可能发生的问题: *电脑蓝屏.电脑冒烟 */ class Lan extends Exception//蓝屏 { Lan(String problem) { super(problem); } } class Fir extends Exception//冒烟 { Fir(String p

JAVA学习第十三课(继承下:抽象类abstract)

抽象:模糊 == 看不懂 继承:发现事物之间的共性关系,并向上抽取,以提高代码的复用性 事物里都具备这个功能,但是这个功能是什么,怎么去做,不知道,这就涉及到了抽象 1.继承:A,B两个类,都有show的功能,实现方式也一样那么就可以向上抽取其共性,做新类,使A,B继承于新类. 2.抽象:A,B两个类,都有show的功能,但是功能的实现方式不一样,那么向上抽取其方法生明,但是内容不一样,那么就用关键字abstract标识,表示抽象函数,那么这个类也必须用abstract标识,表示抽象类 abst

第二十三课

第二十三课第一单元语法部分 Vておく<提前>:预先…… 口语形式:-とく 说明:   A.表示为后面要做的事情事先做好某种准备. B.表示采取某种行为,并使其结果的状态持续下去.   C.有时表示一种临时的措施. 例句:     1 日本へ行く前に日本語を習っておくつもりだ.    2 電気は消さないで 練習: 1.事先打个电话问一.朝までつけておこう.    3 その場で一応の手当てをしておいて.病院へ連れていった.下比较好 2.预先磨好刀. Vてある<客体存续的状态>: 说明:

NeHe OpenGL教程 第二十三课:球面映射

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第二十三课:球面映射 球面映射: 这一个将教会你如何把环境纹理包裹在你的3D模型上,让它看起来象反射了周围的场景一样. 球体环境映射是一个创建快速金属反射效果的方法,但它并不像真实世界里那么精确!我们从18课的代码开始来创建这个教程

穿上华丽的外衣——CSS之旅(码神学习第二十三天)

穿上华丽的外衣--CSS之旅 码神学习第二十三天 学习过程记录: 1.CSS(Cascading Style Sheets,层叠样式表),为了解决内容与表现分离.样式通常存储在样式表中.外部样式表可以提高工作效率. 2.三种不同类型的CSS样式: 答:①内联样式:直接在html标签上定义该标签的CSS样式 ②内部样式:写在html文件中,且包含在<style></style>代码块中 ③外部样式:通过在html中引用外部css文件来控制样式 元素的优先级,就近原则,离元素最近的规则

Java基础--第二十三天

多线程:         多条执行单元 进程:正在运行的应用程序 线程:进程的执行单元,一条执行路径 迅雷下载,360清理 多线程程序实现: 线程依赖于进程存在,Thread类 子类继承 子类重写run方法 调用strart(),让线程启动,调用run()方法 同一个线程对象连续两次启动,报错:表示该线程状态有问题 getName()方法:标志不同线程,获取线程名称 setName():更改线程名字 线程随机性: 程序执行,抢占CPU资源,CPU在多个程序间切换. 第二种实现: 创建类,实现Ru

JAVA学习第二十二课(多线程(二))- (多线程的创建方式一 :继承Thread类)

线程是程序中的执行线程.Java 虚拟机允许应用程序并发地运行多个执行线程. 创建新执行线程有两种方法. 一种方法是将类声明为 Thread 的子类.该子类应重写Thread 类的run 方法.另一种方法是声明实现 Runnable 接口的类.该类然后实现run 方法. 创建线程方式一:继承Thread类 一.创建线程的步骤: 1.定义一个类继承Thread类 2.覆盖Thread中的run()方法 3.直接创建Thread类子类的对象 4.调用start方法开启线程,并调用线程的任务run方法

JAVA学习第二十八课(多线程(七))- 停止线程和多线程面试题

重点掌握 /* * wait 和 sleep 区别? * 1.wait可以指定时间也可以不指定 * sleep必须指定时间 * 2.在同步中,对CPU的执行权和锁的处理不同 * wait释放执行权,释放锁    sleep释放执行权,不释放锁 */ //同步里具备执行资格的线程不止一个,但是能得到锁的只有一个,所以能执行的也只有一个 一.停止线程的方式 不可能让线程一直在运行,所以需要让线程停止 1.定义循环结束标记 一般而言,线程运行代码都是循环的,只要控制了循环就可以结束任务 2.使用int